mirror of
https://github.com/anomalyco/opencode.git
synced 2026-06-02 06:16:48 +02:00
refactor: simplify the changed workflow
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
flex-direction: column;
|
||||
font-synthesis: none;
|
||||
overflow-x: clip;
|
||||
padding-bottom: 5rem;
|
||||
padding-bottom: 0;
|
||||
background: var(--stats-bg);
|
||||
}
|
||||
|
||||
@@ -338,59 +338,160 @@
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] {
|
||||
display: flex;
|
||||
border-top: 1px solid var(--stats-line);
|
||||
position: relative;
|
||||
display: grid;
|
||||
gap: 56px;
|
||||
box-sizing: border-box;
|
||||
min-height: 0;
|
||||
padding: 112px 0 24px;
|
||||
color: var(--stats-text);
|
||||
font-family:
|
||||
"IBM Plex Mono",
|
||||
var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
|
||||
font-size: 14px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] [data-slot="cell"] {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
[data-page="stats"] [data-slot="footer-grid"] {
|
||||
display: grid;
|
||||
grid-template-columns: 120px repeat(4, minmax(0, 1fr));
|
||||
gap: 72px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] [data-slot="cell"] + [data-slot="cell"] {
|
||||
border-left: 1px solid var(--stats-line);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] a {
|
||||
[data-page="stats"] [data-slot="footer-mark"] {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 2rem 0;
|
||||
width: fit-content;
|
||||
color: var(--stats-text);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-mark"] [data-slot="brand-mark"] {
|
||||
width: 24px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 18px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] h2 {
|
||||
color: var(--stats-text);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] nav {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] a,
|
||||
[data-page="stats"] [data-slot="footer-column"] p {
|
||||
color: var(--stats-text);
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] a,
|
||||
[data-page="stats"] [data-slot="footer-column"] p,
|
||||
[data-page="stats"] [data-slot="footer-bottom"] {
|
||||
color: var(--stats-muted);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-column"] a:hover {
|
||||
color: var(--stats-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] a:hover {
|
||||
background: var(--stats-layer);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="legal"] {
|
||||
display: flex;
|
||||
[data-page="stats"] [data-slot="subscribe-button"] {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 32px;
|
||||
margin-top: 4rem;
|
||||
color: var(--stats-faint);
|
||||
text-align: center;
|
||||
font-family:
|
||||
"IBM Plex Mono",
|
||||
var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
|
||||
font-size: 14px;
|
||||
width: fit-content;
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--stats-line);
|
||||
background: var(--stats-bg);
|
||||
color: var(--stats-text) !important;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="legal"] a {
|
||||
color: var(--stats-faint);
|
||||
text-decoration: none;
|
||||
[data-page="stats"] [data-slot="subscribe-button"]:hover {
|
||||
border-color: var(--stats-line-strong);
|
||||
background: var(--stats-layer);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="legal"] a:hover {
|
||||
[data-page="stats"] [data-slot="footer-pattern"] {
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
background: var(--stats-hero-pattern);
|
||||
mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E");
|
||||
mask-position: center top;
|
||||
mask-repeat: repeat;
|
||||
mask-size: 6px 6px;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E");
|
||||
-webkit-mask-position: center top;
|
||||
-webkit-mask-repeat: repeat;
|
||||
-webkit-mask-size: 6px 6px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-bottom"],
|
||||
[data-page="stats"] [data-slot="footer-bottom"] > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-bottom"] {
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-bottom"] > div:first-child {
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="status"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="status"]::before {
|
||||
content: "";
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #198b43;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="theme-toggle"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
padding: 2px;
|
||||
background: var(--stats-layer);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="theme-toggle"] button {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 18px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
color: var(--stats-muted);
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="theme-toggle"] button[data-active="true"] {
|
||||
color: var(--stats-text);
|
||||
background: var(--stats-bg);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="content"] a {
|
||||
@@ -403,8 +504,7 @@
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="chart"],
|
||||
[data-page="stats"] [data-section="newsletter"] {
|
||||
[data-page="stats"] [data-section="chart"] {
|
||||
border-bottom: 1px solid var(--stats-line);
|
||||
box-shadow:
|
||||
inset 1px 0 var(--stats-line),
|
||||
@@ -936,8 +1036,7 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="usage-chart"],
|
||||
[data-page="stats"] [data-component="country-map"] {
|
||||
[data-page="stats"] [data-component="usage-chart"] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -969,8 +1068,7 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="usage-chart"] svg,
|
||||
[data-page="stats"] [data-component="country-map"] svg {
|
||||
[data-page="stats"] [data-component="usage-chart"] svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
@@ -1071,8 +1169,7 @@
|
||||
background: var(--stats-layer-2);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="chart-tooltip"],
|
||||
[data-page="stats"] [data-component="map-tooltip"] {
|
||||
[data-page="stats"] [data-component="chart-tooltip"] {
|
||||
position: absolute;
|
||||
right: auto;
|
||||
top: 96px;
|
||||
@@ -1221,29 +1318,75 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="leaderboard"] {
|
||||
[data-page="stats"] :is([data-section="leaderboard"], [data-section="market-share"], [data-section="token-cost"], [data-section="session-cost"]) {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
box-shadow:
|
||||
inset 0 -1px var(--stats-line),
|
||||
inset 1px 0 var(--stats-line),
|
||||
inset -1px 0 var(--stats-line);
|
||||
padding: 80px 40px;
|
||||
color: var(--stats-text);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="leaderboard-title"] {
|
||||
[data-page="stats"] [data-component="section-bridge"] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
z-index: 2;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
height: 24px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid var(--stats-line);
|
||||
background: var(--stats-bg);
|
||||
color: var(--stats-faint);
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
transform: translate(-50%, -50%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="section-bridge"]:hover {
|
||||
color: var(--stats-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="section-bridge"] i {
|
||||
width: 1px;
|
||||
height: 10px;
|
||||
background: var(--stats-line-strong);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="section-bridge"] strong,
|
||||
[data-page="stats"] [data-component="section-bridge"] b {
|
||||
color: var(--stats-muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="section-title"] {
|
||||
max-width: 1200px;
|
||||
margin-bottom: 40px;
|
||||
color: var(--stats-muted);
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="leaderboard-title"] strong {
|
||||
[data-page="stats"] [data-slot="section-title"] strong {
|
||||
color: var(--stats-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="section-title"] span {
|
||||
color: var(--stats-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="leaderboard"],
|
||||
[data-page="stats"] [data-slot="leaderboard-featured"],
|
||||
[data-page="stats"] [data-slot="leaderboard-compact"],
|
||||
@@ -1447,17 +1590,18 @@
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="market-share"] {
|
||||
--market-gap: 12px;
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
height: 280px;
|
||||
height: 348px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-labels"],
|
||||
[data-page="stats"] [data-slot="market-bars"] {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
grid-template-columns: repeat(var(--market-count), minmax(0, 1fr));
|
||||
gap: var(--market-gap);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-labels"] button,
|
||||
@@ -1475,14 +1619,15 @@
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
color: var(--stats-faint);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-labels"] button[data-active="true"] {
|
||||
color: var(--stats-text);
|
||||
background: transparent;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-bars"] {
|
||||
@@ -1494,6 +1639,7 @@
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-bars"] button[data-active="true"] {
|
||||
@@ -1504,6 +1650,10 @@
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
background: var(--stats-layer-2);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 140ms ease,
|
||||
opacity 140ms ease;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="market-share-list"] {
|
||||
@@ -1511,8 +1661,8 @@
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-template-rows: repeat(3, auto);
|
||||
gap: 8px;
|
||||
margin: 20px 0 0;
|
||||
gap: 8px 10px;
|
||||
margin: 36px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
@@ -1520,20 +1670,38 @@
|
||||
[data-page="stats"] [data-component="market-share-list"] li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
padding: 8px 12px 8px 8px;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 8px;
|
||||
background: var(--stats-layer);
|
||||
border: 1px solid var(--stats-line);
|
||||
font-size: 13px;
|
||||
line-height: 1.1;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color 120ms ease,
|
||||
box-shadow 120ms ease,
|
||||
background 120ms ease;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="market-share-list"] li[data-active="true"],
|
||||
[data-page="stats"] [data-component="market-share-list"] li:focus-visible {
|
||||
border-color: var(--stats-text);
|
||||
background: var(--stats-layer);
|
||||
box-shadow:
|
||||
0 0 0 0.5px color-mix(in srgb, var(--stats-text) 70%, transparent),
|
||||
0 1px 2px -1px #00000014,
|
||||
0 2px 4px #0000000a;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="market-share-list"] span {
|
||||
width: 20px;
|
||||
width: 22px;
|
||||
flex: 0 0 auto;
|
||||
color: var(--stats-muted);
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1562,7 +1730,7 @@
|
||||
|
||||
[data-page="stats"] [data-component="market-share-list"] b {
|
||||
color: var(--stats-muted);
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-footer"] {
|
||||
@@ -1570,15 +1738,17 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 64px;
|
||||
margin-top: 24px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-footer"] p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 166px;
|
||||
font-size: 13px;
|
||||
width: 240px;
|
||||
color: var(--stats-text);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1588,6 +1758,7 @@
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
[data-page="stats"] button[data-component="token-row"] {
|
||||
@@ -1601,8 +1772,8 @@
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: var(--stats-text);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -1612,8 +1783,9 @@
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="token-row"] strong {
|
||||
flex: 0 0 48px;
|
||||
font-weight: 600;
|
||||
flex: 0 0 56px;
|
||||
color: var(--stats-text);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -1622,7 +1794,7 @@
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="token-row"] > span {
|
||||
flex: 0 0 133px;
|
||||
flex: 0 0 132px;
|
||||
overflow: hidden;
|
||||
color: var(--stats-muted);
|
||||
font-weight: 400;
|
||||
@@ -1637,17 +1809,17 @@
|
||||
[data-page="stats"] [data-component="metric-bar"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
gap: 3px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 6px;
|
||||
height: 5px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="metric-bar"] b,
|
||||
[data-page="stats"] [data-component="metric-bar"] em {
|
||||
display: block;
|
||||
height: 6px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="metric-bar"] b {
|
||||
@@ -1661,7 +1833,7 @@
|
||||
|
||||
[data-page="stats"] [data-component="metric-bar"] em {
|
||||
flex: 1;
|
||||
min-width: 12px;
|
||||
min-width: 8px;
|
||||
background: var(--stats-layer-2);
|
||||
}
|
||||
|
||||
@@ -1674,6 +1846,7 @@
|
||||
align-items: flex-end;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="session-heading"] span {
|
||||
@@ -1684,18 +1857,19 @@
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
color: var(--stats-faint);
|
||||
font-size: 11px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="token-tooltip"] {
|
||||
position: absolute;
|
||||
left: 32%;
|
||||
left: 44%;
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
width: 192px;
|
||||
gap: 6px;
|
||||
width: 150px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
background: var(--stats-layer);
|
||||
box-shadow:
|
||||
@@ -1708,8 +1882,8 @@
|
||||
[data-page="stats"] [data-component="token-tooltip"] p {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
font-size: 11px;
|
||||
gap: 10px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
}
|
||||
@@ -1720,27 +1894,23 @@
|
||||
|
||||
[data-page="stats"] [data-slot="token-footer"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
margin-top: 32px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
[data-page="stats"] button[data-component="live-filter"] {
|
||||
[data-page="stats"] [data-component="live-filter"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 0;
|
||||
color: var(--stats-muted);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
[data-page="stats"] button[data-component="live-filter"][data-active="true"] {
|
||||
color: var(--stats-muted);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="live-filter"]::before {
|
||||
content: "";
|
||||
width: 6px;
|
||||
@@ -1753,172 +1923,13 @@
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="toggle"] {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-map"] circle {
|
||||
fill: var(--stats-accent);
|
||||
fill-opacity: 0.14;
|
||||
stroke: var(--stats-accent);
|
||||
stroke-width: 1.5;
|
||||
transition:
|
||||
fill-opacity 120ms ease,
|
||||
stroke-width 120ms ease;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-map"] g[role="button"] {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-map"] g[role="button"][data-active="true"] circle {
|
||||
fill-opacity: 0.28;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-map"] text {
|
||||
fill: var(--stats-text);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="map-tooltip"] {
|
||||
top: 24px;
|
||||
left: 24px;
|
||||
right: auto;
|
||||
min-width: 168px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="map-tooltip"] span,
|
||||
[data-page="stats"] [data-component="map-tooltip"] em {
|
||||
color: var(--stats-muted);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="map-tooltip"] p {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
color: var(--stats-text);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
margin: 20px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] button {
|
||||
display: grid;
|
||||
grid-template-columns: 24px minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--stats-line);
|
||||
border-radius: 0;
|
||||
background: var(--stats-layer);
|
||||
color: var(--stats-muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] button[data-active="true"] {
|
||||
border-color: var(--stats-line-strong);
|
||||
background: var(--stats-layer-2);
|
||||
color: var(--stats-muted);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] span,
|
||||
[data-page="stats"] [data-component="country-list"] em {
|
||||
color: var(--stats-faint);
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] strong {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: var(--stats-text);
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] b {
|
||||
color: var(--stats-muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="country-footer"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="country-footer"] p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--stats-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="country-footer"] span {
|
||||
color: var(--stats-faint);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="newsletter"] {
|
||||
min-height: 272px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 420px;
|
||||
align-items: center;
|
||||
gap: 48px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="newsletter"] div {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="newsletter"] p {
|
||||
color: var(--stats-muted);
|
||||
}
|
||||
|
||||
[data-page="stats"] form {
|
||||
display: flex;
|
||||
border: 1px solid var(--stats-line);
|
||||
background: var(--stats-layer);
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
[data-page="stats"] input {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--stats-text);
|
||||
font: inherit;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
[data-page="stats"] form button {
|
||||
background: var(--stats-text);
|
||||
color: #fff;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
[data-page="stats"] {
|
||||
--color-background: #161616;
|
||||
@@ -1945,8 +1956,7 @@
|
||||
--stats-hero-pattern: #303030;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="chart-tooltip"],
|
||||
[data-page="stats"] [data-component="map-tooltip"] {
|
||||
[data-page="stats"] [data-component="chart-tooltip"] {
|
||||
background: #242424f2;
|
||||
}
|
||||
|
||||
@@ -2026,7 +2036,10 @@
|
||||
|
||||
@media (max-width: 74rem) {
|
||||
[data-page="stats"] [data-section="top-models"],
|
||||
[data-page="stats"] [data-section="leaderboard"] {
|
||||
[data-page="stats"] [data-section="leaderboard"],
|
||||
[data-page="stats"] [data-section="market-share"],
|
||||
[data-page="stats"] [data-section="token-cost"],
|
||||
[data-page="stats"] [data-section="session-cost"] {
|
||||
padding: 64px 32px;
|
||||
}
|
||||
}
|
||||
@@ -2037,16 +2050,11 @@
|
||||
--stats-section-padding: 4rem;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="chart"],
|
||||
[data-page="stats"] [data-section="newsletter"] {
|
||||
[data-page="stats"] [data-section="chart"] {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="newsletter"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="section-header"] {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -2111,40 +2119,52 @@
|
||||
grid-template-rows: none;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="country-list"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="market-footer"] {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="country-footer"] {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="chart-tooltip"],
|
||||
[data-page="stats"] [data-component="map-tooltip"] {
|
||||
[data-page="stats"] [data-component="chart-tooltip"] {
|
||||
position: static;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-section="newsletter"] form {
|
||||
width: 100%;
|
||||
[data-page="stats"] [data-component="footer"] {
|
||||
padding: 88px 24px 24px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-grid"] {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 40px 32px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-mark"] {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-bottom"],
|
||||
[data-page="stats"] [data-slot="footer-bottom"] > div:first-child {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="footer-bottom"] {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 47.999rem) {
|
||||
[data-page="stats"] [data-section="top-models"],
|
||||
[data-page="stats"] [data-section="leaderboard"] {
|
||||
[data-page="stats"] [data-section="leaderboard"],
|
||||
[data-page="stats"] [data-section="market-share"],
|
||||
[data-page="stats"] [data-section="token-cost"],
|
||||
[data-page="stats"] [data-section="session-cost"] {
|
||||
padding: 48px 24px;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-slot="top-models-title"],
|
||||
[data-page="stats"] [data-slot="leaderboard-title"] {
|
||||
[data-page="stats"] [data-slot="section-title"] {
|
||||
margin-bottom: 32px;
|
||||
font-size: 16px;
|
||||
}
|
||||
@@ -2213,12 +2233,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
[data-page="stats"] [data-component="footer"],
|
||||
[data-page="stats"] [data-component="legal"] {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="footer"] [data-slot="cell"] {
|
||||
flex-basis: 50%;
|
||||
[data-page="stats"] [data-slot="footer-grid"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import ibmPlexMonoMediumLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/I
|
||||
import ibmPlexMonoSemiBoldLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/IBMPlexMono-SemiBold-Latin1.woff2?url"
|
||||
import ibmPlexMonoBoldLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/IBMPlexMono-Bold-Latin1.woff2?url"
|
||||
import {
|
||||
type CountryEntry,
|
||||
getStatsHomeData,
|
||||
type LeaderboardEntry,
|
||||
type MarketDay,
|
||||
@@ -51,20 +50,6 @@ const usageColors = [
|
||||
"#ff6467",
|
||||
]
|
||||
const marketColors = ["#ed6aff", "#a684ff", "#7c86ff", "#51a2ff", "#00d3f2", "#00d5be", "#00bc7d", "#9ae600", "#ffb900"]
|
||||
const countryPositions = [
|
||||
{ x: 112, y: 96 },
|
||||
{ x: 284, y: 144 },
|
||||
{ x: 472, y: 92 },
|
||||
{ x: 642, y: 154 },
|
||||
{ x: 800, y: 96 },
|
||||
{ x: 172, y: 234 },
|
||||
{ x: 362, y: 250 },
|
||||
{ x: 552, y: 236 },
|
||||
{ x: 744, y: 252 },
|
||||
{ x: 48, y: 184 },
|
||||
{ x: 892, y: 198 },
|
||||
{ x: 456, y: 176 },
|
||||
] as const
|
||||
|
||||
type UsageProduct = (typeof products)[number]
|
||||
type TokenProduct = (typeof tokenProducts)[number]
|
||||
@@ -102,15 +87,12 @@ export default function StatsHome() {
|
||||
<MarketShareSection data={stats().market} />
|
||||
<TokenCostSection data={stats().tokenCost} />
|
||||
<SessionCostSection data={stats().sessionCost} />
|
||||
<CountrySection data={stats().country} />
|
||||
<Newsletter />
|
||||
</>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
<Legal />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -244,6 +226,25 @@ function ChartSection(props: {
|
||||
)
|
||||
}
|
||||
|
||||
function SectionTitle(props: { title: string; description: string }) {
|
||||
return (
|
||||
<p data-slot="section-title">
|
||||
<strong>{props.title}.</strong> <span>{props.description}</span>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
function SectionBridge(props: { label: string; href: string }) {
|
||||
return (
|
||||
<a data-component="section-bridge" href={props.href}>
|
||||
<span>LEAN MORE</span>
|
||||
<i />
|
||||
<strong>{props.label}</strong>
|
||||
<b>▸</b>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyState(props: { title: string; description: string }) {
|
||||
return (
|
||||
<div data-component="empty-state">
|
||||
@@ -678,10 +679,10 @@ function LeaderboardSection(props: { data: StatsHomeData["leaderboard"] }) {
|
||||
|
||||
return (
|
||||
<section id="leaderboard" data-section="leaderboard">
|
||||
<p data-slot="leaderboard-title">
|
||||
<strong>Leaderboard.</strong>{" "}
|
||||
<span>Shown are the sum of prompt and completion tokens per model, including reasoning tokens.</span>
|
||||
</p>
|
||||
<SectionTitle
|
||||
title="Leaderboard"
|
||||
description="Shown are the sum of prompt and completion tokens per model, including reasoning tokens."
|
||||
/>
|
||||
<Show
|
||||
when={data().length > 0}
|
||||
fallback={
|
||||
@@ -771,44 +772,99 @@ function formatChange(value: number) {
|
||||
function MarketShareSection(props: { data: StatsHomeData["market"] }) {
|
||||
const [range, setRange] = createSignal<UsageRange>("1W")
|
||||
const [activeIndex, setActiveIndex] = createSignal(2)
|
||||
const [activeAuthor, setActiveAuthor] = createSignal<string>()
|
||||
const [inspecting, setInspecting] = createSignal(false)
|
||||
const data = createMemo(() => props.data[range()])
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(data().length - 1, 0)))
|
||||
const activeDay = createMemo(() => data()[selectedIndex()])
|
||||
|
||||
return (
|
||||
<ChartSection id="market-share" title="Market Share" description="Compare token share by model author.">
|
||||
<section
|
||||
id="market-share"
|
||||
data-section="market-share"
|
||||
onPointerLeave={(event) => {
|
||||
if (event.pointerType === "touch") return
|
||||
setActiveAuthor(undefined)
|
||||
setInspecting(false)
|
||||
}}
|
||||
>
|
||||
<SectionBridge label="LEADERBOARD" href="#leaderboard" />
|
||||
<SectionTitle title="Market Share" description="Compare token share by model author." />
|
||||
<Show
|
||||
when={activeDay()}
|
||||
fallback={<EmptyState title="No market data" description="No model_stat rows matched this range." />}
|
||||
>
|
||||
{(day) => (
|
||||
<>
|
||||
<MarketShare data={data()} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
<MarketShareList data={day().authors} />
|
||||
<MarketShare
|
||||
data={data()}
|
||||
activeIndex={selectedIndex()}
|
||||
activeAuthor={activeAuthor()}
|
||||
inspecting={inspecting()}
|
||||
onActiveIndexChange={(index) => {
|
||||
setActiveIndex(index)
|
||||
setInspecting(true)
|
||||
}}
|
||||
onActiveAuthorChange={(author) => {
|
||||
setActiveAuthor(author)
|
||||
setInspecting(true)
|
||||
}}
|
||||
/>
|
||||
<MarketShareList
|
||||
data={day().authors}
|
||||
activeAuthor={activeAuthor()}
|
||||
onActiveAuthorChange={(author) => {
|
||||
setActiveAuthor(author)
|
||||
setInspecting(true)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Show>
|
||||
<div data-slot="market-footer">
|
||||
<p>
|
||||
<span>[*]</span>
|
||||
<strong>{activeDay()?.date ?? "No data"}</strong>
|
||||
<strong>{inspecting() ? formatMarketDate(activeDay()) : formatMarketRange(data())}</strong>
|
||||
</p>
|
||||
<FilterPills items={ranges} selected={range()} label="Date range" variant="range" onSelect={setRange} />
|
||||
<FilterPills
|
||||
items={ranges}
|
||||
selected={range()}
|
||||
label="Date range"
|
||||
variant="range"
|
||||
onSelect={(item) => {
|
||||
setRange(item)
|
||||
setActiveAuthor(undefined)
|
||||
setInspecting(false)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</ChartSection>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function MarketShare(props: { data: MarketDay[]; activeIndex: number; onActiveIndexChange: (index: number) => void }) {
|
||||
function MarketShare(props: {
|
||||
data: MarketDay[]
|
||||
activeIndex: number
|
||||
activeAuthor: string | undefined
|
||||
inspecting: boolean
|
||||
onActiveIndexChange: (index: number) => void
|
||||
onActiveAuthorChange: (author: string) => void
|
||||
}) {
|
||||
return (
|
||||
<div data-component="market-share" role="img" aria-label="Market share by model author">
|
||||
<div
|
||||
data-component="market-share"
|
||||
role="img"
|
||||
aria-label="Market share by model author"
|
||||
style={{ "--market-count": props.data.length } as JSX.CSSProperties}
|
||||
>
|
||||
<div data-slot="market-labels">
|
||||
<For each={props.data}>
|
||||
{(day, index) => (
|
||||
<button
|
||||
type="button"
|
||||
data-active={props.activeIndex === index() ? "true" : undefined}
|
||||
data-active={props.inspecting && props.activeIndex === index() ? "true" : undefined}
|
||||
onClick={() => props.onActiveIndexChange(index())}
|
||||
onPointerEnter={() => props.onActiveIndexChange(index())}
|
||||
>
|
||||
<span>{formatTrillions(day.total)}</span>
|
||||
<span>{day.date}</span>
|
||||
@@ -822,16 +878,40 @@ function MarketShare(props: { data: MarketDay[]; activeIndex: number; onActiveIn
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`${day.date} ${formatTrillions(day.total)}`}
|
||||
data-active={props.activeIndex === index() ? "true" : undefined}
|
||||
data-active={props.inspecting && props.activeIndex === index() ? "true" : undefined}
|
||||
onClick={() => props.onActiveIndexChange(index())}
|
||||
onPointerEnter={() => props.onActiveIndexChange(index())}
|
||||
>
|
||||
<For each={day.authors}>
|
||||
{(author, authorIndex) => (
|
||||
<span
|
||||
data-active={props.activeAuthor === author.author ? "true" : undefined}
|
||||
data-muted={
|
||||
props.activeAuthor !== undefined && props.activeAuthor !== author.author ? "true" : undefined
|
||||
}
|
||||
style={{
|
||||
"background-color": props.activeIndex === index() ? marketColors[authorIndex()] : undefined,
|
||||
"background-color": getMarketSegmentColor(
|
||||
author.author,
|
||||
marketColors[authorIndex()] ?? "var(--stats-text)",
|
||||
props.activeAuthor,
|
||||
),
|
||||
"flex-grow": author.share,
|
||||
}}
|
||||
onPointerEnter={(event) => {
|
||||
event.stopPropagation()
|
||||
props.onActiveIndexChange(index())
|
||||
props.onActiveAuthorChange(author.author)
|
||||
}}
|
||||
onPointerDown={(event) => {
|
||||
event.stopPropagation()
|
||||
props.onActiveIndexChange(index())
|
||||
props.onActiveAuthorChange(author.author)
|
||||
}}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation()
|
||||
props.onActiveIndexChange(index())
|
||||
props.onActiveAuthorChange(author.author)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
@@ -843,12 +923,28 @@ function MarketShare(props: { data: MarketDay[]; activeIndex: number; onActiveIn
|
||||
)
|
||||
}
|
||||
|
||||
function MarketShareList(props: { data: MarketDay["authors"] }) {
|
||||
function MarketShareList(props: {
|
||||
data: MarketDay["authors"]
|
||||
activeAuthor: string | undefined
|
||||
onActiveAuthorChange: (author: string) => void
|
||||
}) {
|
||||
return (
|
||||
<ol data-component="market-share-list">
|
||||
<For each={props.data}>
|
||||
{(item, index) => (
|
||||
<li>
|
||||
<li
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${item.author} ${formatTrillions(item.tokens)} ${item.share.toFixed(1)} percent`}
|
||||
data-active={props.activeAuthor === item.author ? "true" : undefined}
|
||||
onPointerEnter={() => props.onActiveAuthorChange(item.author)}
|
||||
onFocus={() => props.onActiveAuthorChange(item.author)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key !== "Enter" && event.key !== " ") return
|
||||
event.preventDefault()
|
||||
props.onActiveAuthorChange(item.author)
|
||||
}}
|
||||
>
|
||||
<span>{String(index() + 1).padStart(2, "0")}</span>
|
||||
<i style={{ background: marketColors[index()] }} />
|
||||
<strong>{item.author}</strong>
|
||||
@@ -861,25 +957,47 @@ function MarketShareList(props: { data: MarketDay["authors"] }) {
|
||||
)
|
||||
}
|
||||
|
||||
function getMarketSegmentColor(author: string, color: string, activeAuthor: string | undefined) {
|
||||
if (!activeAuthor) return color
|
||||
if (activeAuthor === author) return color
|
||||
return "var(--stats-bar-idle)"
|
||||
}
|
||||
|
||||
function formatTrillions(value: number) {
|
||||
return `${value.toFixed(value >= 10 ? 0 : 1)}T`
|
||||
}
|
||||
|
||||
function formatMarketDate(day: MarketDay | undefined) {
|
||||
if (!day) return "No data"
|
||||
return `${day.date} ${new Date().getFullYear()}`
|
||||
}
|
||||
|
||||
function formatMarketRange(data: MarketDay[]) {
|
||||
const first = data[0]?.date
|
||||
const last = data[data.length - 1]?.date
|
||||
if (!first || !last) return "No data"
|
||||
const year = new Date().getFullYear()
|
||||
return `${first} ${year} → ${last} ${year}`
|
||||
}
|
||||
|
||||
function TokenCostSection(props: { data: StatsHomeData["tokenCost"] }) {
|
||||
const [product, setProduct] = createSignal<TokenProduct>("Zen")
|
||||
const [activeIndex, setActiveIndex] = createSignal(2)
|
||||
const data = createMemo(() => props.data[product()])
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(data().length - 1, 0)))
|
||||
const visible = createMemo(() => data().slice(0, 13))
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(visible().length - 1, 0)))
|
||||
|
||||
return (
|
||||
<ChartSection id="token-cost" title="Token Cost" description="Price per 1M tokens.">
|
||||
<section id="token-cost" data-section="token-cost">
|
||||
<SectionBridge label="MARKET SHARE" href="#market-share" />
|
||||
<SectionTitle title="Token Cost" description="Price per 1M tokens." />
|
||||
<Show
|
||||
when={data().length > 0}
|
||||
when={visible().length > 0}
|
||||
fallback={
|
||||
<EmptyState title="No token cost data" description="No cost-bearing model_stat rows matched this product." />
|
||||
}
|
||||
>
|
||||
<TokenCostChart data={data()} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
<TokenCostChart data={visible()} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
</Show>
|
||||
<div data-slot="token-footer">
|
||||
<FilterPills
|
||||
@@ -889,8 +1007,9 @@ function TokenCostSection(props: { data: StatsHomeData["tokenCost"] }) {
|
||||
variant="product"
|
||||
onSelect={setProduct}
|
||||
/>
|
||||
<LiveIndicator />
|
||||
</div>
|
||||
</ChartSection>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -921,7 +1040,7 @@ function TokenCostChart(props: {
|
||||
</For>
|
||||
<Show when={active()}>
|
||||
{(item) => (
|
||||
<div data-component="token-tooltip" style={{ top: `${props.activeIndex * 28 + 2}px` }}>
|
||||
<div data-component="token-tooltip" style={{ top: `${props.activeIndex * 36 + 2}px` }}>
|
||||
<p>
|
||||
<span>Input</span>
|
||||
<strong>{formatDollars(item().input)}</strong>
|
||||
@@ -958,12 +1077,15 @@ function SessionCostSection(props: { data: StatsHomeData["sessionCost"] }) {
|
||||
const [product, setProduct] = createSignal<TokenProduct>("Zen")
|
||||
const [activeIndex, setActiveIndex] = createSignal(2)
|
||||
const data = createMemo(() => props.data[product()])
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(data().length - 1, 0)))
|
||||
const visible = createMemo(() => data().slice(0, 16))
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(visible().length - 1, 0)))
|
||||
|
||||
return (
|
||||
<ChartSection id="session-cost" title="Session Cost" description="Average cost per session.">
|
||||
<section id="session-cost" data-section="session-cost">
|
||||
<SectionBridge label="TOKEN COST" href="#token-cost" />
|
||||
<SectionTitle title="Session Cost" description="Average cost per session." />
|
||||
<Show
|
||||
when={data().length > 0}
|
||||
when={visible().length > 0}
|
||||
fallback={
|
||||
<EmptyState
|
||||
title="No session cost data"
|
||||
@@ -971,7 +1093,7 @@ function SessionCostSection(props: { data: StatsHomeData["sessionCost"] }) {
|
||||
/>
|
||||
}
|
||||
>
|
||||
<SessionCostChart data={data()} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
<SessionCostChart data={visible()} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
</Show>
|
||||
<div data-slot="token-footer">
|
||||
<FilterPills
|
||||
@@ -981,8 +1103,9 @@ function SessionCostSection(props: { data: StatsHomeData["sessionCost"] }) {
|
||||
variant="product"
|
||||
onSelect={setProduct}
|
||||
/>
|
||||
<LiveIndicator />
|
||||
</div>
|
||||
</ChartSection>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1024,7 +1147,7 @@ function SessionCostChart(props: {
|
||||
<div
|
||||
data-component="token-tooltip"
|
||||
data-variant="session"
|
||||
style={{ top: `${props.activeIndex * 28 + 21}px` }}
|
||||
style={{ top: `${props.activeIndex * 36 + 28}px` }}
|
||||
>
|
||||
<p>
|
||||
<span>Cost/Session</span>
|
||||
@@ -1041,6 +1164,10 @@ function SessionCostChart(props: {
|
||||
)
|
||||
}
|
||||
|
||||
function LiveIndicator() {
|
||||
return <span data-component="live-filter">Live</span>
|
||||
}
|
||||
|
||||
function formatTokenCount(value: number) {
|
||||
if (value >= 1_000_000) return `${Number((value / 1_000_000).toFixed(1))}M`
|
||||
return `${Math.round(value / 1_000)}K`
|
||||
@@ -1050,141 +1177,6 @@ function formatSessionCost(value: number) {
|
||||
return `$${value.toFixed(4)}`
|
||||
}
|
||||
|
||||
function CountrySection(props: { data: StatsHomeData["country"] }) {
|
||||
const [range, setRange] = createSignal<UsageRange>("1W")
|
||||
const data = createMemo(() => props.data[range()])
|
||||
|
||||
return (
|
||||
<ChartSection title="Token by Country" description="Country-level token totals from geo_stat.">
|
||||
<Show
|
||||
when={data().length > 0}
|
||||
fallback={<EmptyState title="No country data" description="No geo_stat rows matched this range." />}
|
||||
>
|
||||
<CountryChart data={data()} />
|
||||
</Show>
|
||||
<div data-slot="country-footer">
|
||||
<p>
|
||||
<span>[*]</span>
|
||||
<strong>Top countries by tokens</strong>
|
||||
</p>
|
||||
<FilterPills items={ranges} selected={range()} label="Date range" variant="range" onSelect={setRange} />
|
||||
</div>
|
||||
</ChartSection>
|
||||
)
|
||||
}
|
||||
|
||||
function CountryChart(props: { data: CountryEntry[] }) {
|
||||
const [activeIndex, setActiveIndex] = createSignal(0)
|
||||
const selectedIndex = createMemo(() => Math.min(activeIndex(), Math.max(props.data.length - 1, 0)))
|
||||
const active = createMemo(() => props.data[selectedIndex()])
|
||||
const max = createMemo(() => Math.max(0.0001, ...props.data.map((item) => item.tokens)))
|
||||
|
||||
return (
|
||||
<div data-component="country-map">
|
||||
<svg viewBox="0 0 920 320" role="img" aria-label="Country token share bubble chart">
|
||||
<For each={props.data.slice(0, countryPositions.length)}>
|
||||
{(item, index) => {
|
||||
const position = countryPositions[index()]
|
||||
const radius = 18 + Math.sqrt(item.tokens / max()) * 58
|
||||
return (
|
||||
<g
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${formatCountry(item.country)} ${formatTokens(item.tokens)}`}
|
||||
data-active={selectedIndex() === index() ? "true" : undefined}
|
||||
onPointerEnter={() => setActiveIndex(index())}
|
||||
onClick={() => setActiveIndex(index())}
|
||||
onFocus={() => setActiveIndex(index())}
|
||||
>
|
||||
<circle cx={position.x} cy={position.y} r={radius} />
|
||||
<text x={position.x} y={position.y + 4} text-anchor="middle">
|
||||
{item.country}
|
||||
</text>
|
||||
</g>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</svg>
|
||||
<Show when={active()}>
|
||||
{(item) => (
|
||||
<div data-component="map-tooltip">
|
||||
<strong>{formatCountry(item().country)}</strong>
|
||||
<span>{item().continent || "Unknown region"}</span>
|
||||
<p>
|
||||
<b>{formatTokens(item().tokens)}</b>
|
||||
<em>{item().share.toFixed(1)}%</em>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
<CountryList data={props.data.slice(0, 8)} activeIndex={selectedIndex()} onActiveIndexChange={setActiveIndex} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CountryList(props: {
|
||||
data: CountryEntry[]
|
||||
activeIndex: number
|
||||
onActiveIndexChange: (index: number) => void
|
||||
}) {
|
||||
return (
|
||||
<ol data-component="country-list">
|
||||
<For each={props.data}>
|
||||
{(item, index) => (
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
data-active={props.activeIndex === index() ? "true" : undefined}
|
||||
onClick={() => props.onActiveIndexChange(index())}
|
||||
onPointerEnter={() => props.onActiveIndexChange(index())}
|
||||
>
|
||||
<span>{String(item.rank).padStart(2, "0")}</span>
|
||||
<strong>{formatCountry(item.country)}</strong>
|
||||
<em>{formatTokens(item.tokens)}</em>
|
||||
<b>{item.share.toFixed(1)}%</b>
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ol>
|
||||
)
|
||||
}
|
||||
|
||||
function formatCountry(country: string) {
|
||||
const known: Record<string, string> = {
|
||||
AU: "Australia",
|
||||
BR: "Brazil",
|
||||
CA: "Canada",
|
||||
CN: "China",
|
||||
DE: "Germany",
|
||||
FR: "France",
|
||||
GB: "United Kingdom",
|
||||
IN: "India",
|
||||
JP: "Japan",
|
||||
KR: "South Korea",
|
||||
NL: "Netherlands",
|
||||
SG: "Singapore",
|
||||
US: "United States",
|
||||
ZZ: "Unknown",
|
||||
}
|
||||
return known[country] ?? country
|
||||
}
|
||||
|
||||
function Newsletter() {
|
||||
return (
|
||||
<section data-section="newsletter">
|
||||
<div>
|
||||
<h2>Be the first to know when we release new products</h2>
|
||||
<p>Join the waitlist for early access.</p>
|
||||
</div>
|
||||
<form>
|
||||
<input type="email" placeholder="Email address" />
|
||||
<button>Subscribe</button>
|
||||
</form>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function Header() {
|
||||
const [menuOpen, setMenuOpen] = createSignal(false)
|
||||
const [menuViewport, setMenuViewport] = createSignal(false)
|
||||
@@ -1290,10 +1282,7 @@ function Header() {
|
||||
function StatsWordmark() {
|
||||
return (
|
||||
<span data-slot="stats-wordmark" aria-hidden="true">
|
||||
<svg data-slot="brand-mark" width="19" height="24" viewBox="0 0 19 24" fill="none">
|
||||
<path opacity="0.2" d="M14.25 19.2H4.75V9.6H14.25V19.2Z" fill="currentColor" />
|
||||
<path d="M14.25 4.8H4.75V19.2H14.25V4.8ZM19 24H0V0H19V24Z" fill="currentColor" />
|
||||
</svg>
|
||||
<StatsMark />
|
||||
<svg data-slot="brand-label" width="51" height="14" viewBox="0 0 50.8509 14" fill="none">
|
||||
<path
|
||||
d="M46.2359 14C45.2276 14 44.3356 13.819 43.56 13.4571C42.7973 13.0822 42.138 12.5328 41.5822 11.8089L43.1722 10.277C43.56 10.807 44.0124 11.2142 44.5295 11.4986C45.0466 11.7701 45.6283 11.9058 46.2747 11.9058C47.7225 11.9058 48.4464 11.2465 48.4464 9.92798C48.4464 9.38504 48.3172 8.97138 48.0586 8.68698C47.8001 8.40259 47.3735 8.19575 46.7788 8.06648L45.596 7.8338C44.3679 7.57525 43.463 7.13573 42.8813 6.51524C42.2996 5.89474 42.0088 5.02862 42.0088 3.9169C42.0088 2.62419 42.3901 1.6482 43.1528 0.98892C43.9284 0.32964 45.0272 0 46.4492 0C47.4187 0 48.2461 0.161588 48.9312 0.484764C49.6293 0.795014 50.2239 1.28624 50.7151 1.95845L49.1251 3.45152C48.789 2.99908 48.4076 2.66297 47.9811 2.44321C47.5545 2.21053 47.0309 2.09418 46.4104 2.09418C45.7253 2.09418 45.2211 2.22992 44.898 2.50139C44.5748 2.77285 44.4132 3.21237 44.4132 3.81995C44.4132 4.3241 44.536 4.71191 44.7816 4.98338C45.0401 5.25485 45.4538 5.45522 46.0226 5.58449L47.2054 5.83656C47.8647 5.97876 48.4206 6.15328 48.873 6.36011C49.3384 6.56694 49.7133 6.82548 49.9977 7.13573C50.295 7.44598 50.5083 7.8144 50.6376 8.241C50.7798 8.65466 50.8509 9.14589 50.8509 9.71468C50.8509 11.1108 50.4501 12.1773 49.6486 12.9141C48.8601 13.638 47.7225 14 46.2359 14Z"
|
||||
@@ -1320,42 +1309,114 @@ function StatsWordmark() {
|
||||
)
|
||||
}
|
||||
|
||||
function StatsMark() {
|
||||
return (
|
||||
<svg data-slot="brand-mark" width="19" height="24" viewBox="0 0 19 24" fill="none" aria-hidden="true">
|
||||
<path opacity="0.2" d="M14.25 19.2H4.75V9.6H14.25V19.2Z" fill="currentColor" />
|
||||
<path d="M14.25 4.8H4.75V19.2H14.25V4.8ZM19 24H0V0H19V24Z" fill="currentColor" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
const modelStats = [
|
||||
{ href: "#top-models", label: "Top Models" },
|
||||
{ href: "#leaderboard", label: "Leaderboard" },
|
||||
{ href: "#market-share", label: "Market Share" },
|
||||
{ href: "#token-cost", label: "Token Cost" },
|
||||
{ href: "#session-cost", label: "Session Cost" },
|
||||
]
|
||||
const legal = [
|
||||
{ href: "https://opencode.ai/legal/terms-of-service", label: "Terms of service" },
|
||||
{ href: "https://opencode.ai/legal/privacy-policy", label: "Privacy policy" },
|
||||
]
|
||||
const connect = [
|
||||
{ href: "mailto:hello@opencode.ai", label: "Contact us" },
|
||||
{ href: "https://opencode.ai/discord", label: "Community" },
|
||||
{ href: "https://x.com/opencode_ai", label: "X" },
|
||||
{ href: "https://github.com/sst/opencode", label: "GitHub" },
|
||||
{ href: "https://youtube.com/@opencode-ai", label: "YouTube" },
|
||||
]
|
||||
|
||||
return (
|
||||
<footer data-component="footer">
|
||||
<div data-slot="cell">
|
||||
<a href="https://github.com/sst/opencode" target="_blank" rel="noreferrer">
|
||||
GitHub
|
||||
<SectionBridge label="SESSION COST" href="#session-cost" />
|
||||
<div data-slot="footer-grid">
|
||||
<a data-slot="footer-mark" href="/" aria-label="OpenCode home">
|
||||
<StatsMark />
|
||||
</a>
|
||||
<FooterColumn title="Model Stats" links={modelStats} />
|
||||
<FooterColumn title="Legal" links={legal} />
|
||||
<FooterColumn title="Connect" links={connect} />
|
||||
<div data-slot="footer-column">
|
||||
<h2>Newsletter</h2>
|
||||
<p>Be the first to know about new releases.</p>
|
||||
<a data-slot="subscribe-button" href="https://opencode.ai/">
|
||||
Subscribe
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div data-slot="cell">
|
||||
<a href="https://opencode.ai/docs">Docs</a>
|
||||
</div>
|
||||
<div data-slot="cell">
|
||||
<a href="https://opencode.ai/changelog">Changelog</a>
|
||||
</div>
|
||||
<div data-slot="cell">
|
||||
<a href="https://x.com/opencode_ai">X</a>
|
||||
<div data-slot="footer-pattern" aria-hidden="true" />
|
||||
<div data-slot="footer-bottom">
|
||||
<div>
|
||||
<span>© 2026 Anomaly Innovations Inc.</span>
|
||||
<span data-slot="status">All systems Operational</span>
|
||||
</div>
|
||||
<div data-slot="theme-toggle" aria-label="Theme preference">
|
||||
<button type="button" aria-label="Use dark theme">
|
||||
<MoonIcon />
|
||||
</button>
|
||||
<button type="button" aria-label="Use light theme">
|
||||
<SunIcon />
|
||||
</button>
|
||||
<button type="button" aria-label="Use system theme" data-active="true">
|
||||
<MonitorIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
function Legal() {
|
||||
function FooterColumn(props: { title: string; links: { href: string; label: string }[] }) {
|
||||
return (
|
||||
<div data-component="legal">
|
||||
<span>
|
||||
©{new Date().getFullYear()} <a href="https://anoma.ly">Anomaly</a>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://opencode.ai/brand">Brand</a>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://opencode.ai/legal/privacy-policy">Privacy</a>
|
||||
</span>
|
||||
<span>
|
||||
<a href="https://opencode.ai/legal/terms-of-service">Terms</a>
|
||||
</span>
|
||||
<div data-slot="footer-column">
|
||||
<h2>{props.title}</h2>
|
||||
<nav aria-label={props.title}>
|
||||
<For each={props.links}>
|
||||
{(link) => (
|
||||
<a href={link.href} target={link.href.startsWith("http") ? "_blank" : undefined} rel="noreferrer">
|
||||
{link.label}
|
||||
</a>
|
||||
)}
|
||||
</For>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function MoonIcon() {
|
||||
return (
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
||||
<path d="M8.8 7.9A4.3 4.3 0 0 1 4.1 3.2A3.9 3.9 0 1 0 8.8 7.9Z" stroke="currentColor" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function SunIcon() {
|
||||
return (
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
||||
<path d="M6 3.5V2M6 10V8.5M8.5 6H10M2 6H3.5M7.75 4.25L8.8 3.2M3.2 8.8L4.25 7.75M4.25 4.25L3.2 3.2M8.8 8.8L7.75 7.75" stroke="currentColor" />
|
||||
<circle cx="6" cy="6" r="1.7" stroke="currentColor" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function MonitorIcon() {
|
||||
return (
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
||||
<path d="M2 3H10V8H2V3Z" stroke="currentColor" />
|
||||
<path d="M4.5 10H7.5M6 8V10" stroke="currentColor" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user