Skip to content

Commit ca0f993

Browse files
asizikovCopilot
andcommitted
refactor: migrate all views and chart containers to Tailwind
Replace BEM CSS classes with Tailwind utility classes for: - OverviewView (summary cards, banners, charts grid, next steps) - UsersView (sortable table, pagination, editable cells) - UserDetailsView (breadcrumb, per-model breakdown, comparison) - ModelsView (model selector, breakdown table, info banners) - ProductsView (stacked bars, legend, expandable rows) - OrganizationsView (tab tables, sorting, comparison) - CostCentersView (tab tables, entitlement banners) - ReportGuideView (sections, CSV table, annotations) - FaqView (definition lists, cards) - Chart containers (DualAxisLineChart, DailyStackedBarChart, MultiSeriesStackedBarChart) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6f652f2 commit ca0f993

12 files changed

Lines changed: 439 additions & 423 deletions

src/components/DailyStackedBarChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export function DailyStackedBarChart({
144144
}
145145

146146
return (
147-
<div className="chart-container" style={{ height }}>
147+
<div className="bg-bg-default border border-border-default rounded-md p-4 w-full [&_canvas]:w-full!" style={{ height }}>
148148
<Bar data={chartData} options={options} />
149149
</div>
150150
)

src/components/DualAxisLineChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export function DualAxisLineChart({
144144
}
145145

146146
return (
147-
<div className="chart-container" style={{ height }}>
147+
<div className="bg-bg-default border border-border-default rounded-md p-4 w-full [&_canvas]:w-full!" style={{ height }}>
148148
<Line data={chartData} options={options} />
149149
</div>
150150
)

src/components/MultiSeriesStackedBarChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export function MultiSeriesStackedBarChart({
120120
}
121121

122122
return (
123-
<div className="chart-container" style={{ height }}>
123+
<div className="bg-bg-default border border-border-default rounded-md p-4 w-full [&_canvas]:w-full!" style={{ height }}>
124124
<Bar data={chartData} options={options} />
125125
</div>
126126
)

src/views/CostCentersView.tsx

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
7272

7373
if (data.costCenters.length === 0) {
7474
return (
75-
<section className="cost-centers-view">
76-
<h2 className="cost-centers-view__heading">Cost Centers</h2>
77-
<div className="cost-centers-view__empty">No cost centers found in this report.</div>
75+
<section className="flex flex-col gap-5">
76+
<h2 className="m-0 text-2xl font-bold text-fg-default">Cost Centers</h2>
77+
<div className="bg-bg-default border border-border-default rounded-md p-6 text-center text-fg-muted text-sm">No cost centers found in this report.</div>
7878
</section>
7979
)
8080
}
@@ -85,21 +85,21 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
8585
const hasCosts = totals && (totals.grossAmount > 0 || totals.aicGrossAmount > 0)
8686

8787
return (
88-
<section className="cost-centers-view">
89-
<div className="cost-centers-view__header">
90-
<div className="cost-centers-view__title">
91-
<h2 className="cost-centers-view__heading">Cost Centers</h2>
92-
<span className="cost-centers-view__count">{data.costCenters.length.toLocaleString()} total</span>
88+
<section className="flex flex-col gap-5">
89+
<div className="flex flex-col gap-3 mb-2">
90+
<div className="flex items-baseline gap-3">
91+
<h2 className="m-0 text-2xl font-bold text-fg-default">Cost Centers</h2>
92+
<span className="text-sm font-medium text-fg-muted">{data.costCenters.length.toLocaleString()} total</span>
9393
</div>
94-
<select className="cost-centers-view__select" value={selectedCostCenterName} onChange={handleSelectChange}>
94+
<select className="border border-border-default rounded-md py-2.5 px-3 text-sm max-w-[500px] text-fg-default bg-bg-default focus-visible:outline-2 focus-visible:outline-app-accent focus-visible:outline-offset-2" value={selectedCostCenterName} onChange={handleSelectChange}>
9595
{selectOptions}
9696
</select>
9797
</div>
9898

9999
{selectedCostCenter && totals && (
100100
<>
101101
{hasCosts && periodLabel && (
102-
<p className="comparison-framing">
102+
<p className="text-base font-normal text-center mb-1 text-fg-default">
103103
{savings > 0 ? (
104104
<>
105105
<strong>{selectedCostCenterName}</strong>'s <strong>{periodLabel}</strong> usage would cost{' '}
@@ -118,42 +118,42 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
118118
</p>
119119
)}
120120

121-
<div className="comparison-grid">
122-
<div className="card comparison-card">
123-
<div className="comparison-card__label">Current billing (PRUs)</div>
124-
<div className="comparison-card__big-number">{formatUsd(totals.netAmount)}</div>
125-
<div className="comparison-card__period">{totals.requests.toLocaleString()} PRUs</div>
126-
<div className="comparison-card__rate">1 PRU = $0.04</div>
127-
<div className="comparison-card__breakdown">
128-
<div className="comparison-card__breakdown-row">
121+
<div className="grid grid-cols-2 gap-4 mb-6">
122+
<div className="bg-bg-default border border-border-default rounded-md text-center py-7 px-5">
123+
<div className="text-[13px] font-medium text-fg-muted uppercase tracking-[0.5px] mb-3">Current billing (PRUs)</div>
124+
<div className="text-4xl font-bold leading-[1.2] text-fg-default">{formatUsd(totals.netAmount)}</div>
125+
<div className="text-sm text-fg-default mt-1.5">{totals.requests.toLocaleString()} PRUs</div>
126+
<div className="text-xs text-fg-muted mt-1">1 PRU = $0.04</div>
127+
<div className="mt-4 pt-3 border-t border-border-default w-full flex flex-col gap-1.5 text-left">
128+
<div className="flex justify-between items-center text-[13px] text-fg-default tabular-nums">
129129
<span>Gross cost</span>
130130
<span>{formatUsd(totals.grossAmount)}</span>
131131
</div>
132-
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--muted">
132+
<div className="flex justify-between items-center text-[13px] text-fg-muted tabular-nums">
133133
<span>Discounts</span>
134134
<span>{formatUsd(totals.discountAmount)}</span>
135135
</div>
136-
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--total">
136+
<div className="flex justify-between items-center text-[13px] text-fg-default tabular-nums pt-1.5 border-t border-border-default font-semibold">
137137
<span>Net cost</span>
138138
<span>{formatUsd(totals.netAmount)}</span>
139139
</div>
140140
</div>
141141
</div>
142-
<div className="card comparison-card">
143-
<div className="comparison-card__label">AI Credits-based billing (AICs)</div>
144-
<div className="comparison-card__big-number comparison-card__big-number--aic">{formatUsd(totals.aicNetAmount)}</div>
145-
<div className="comparison-card__period">{formatAic(totals.aicQuantity)} AICs</div>
146-
<div className="comparison-card__rate">1 AIC = $0.01</div>
147-
<div className="comparison-card__breakdown">
148-
<div className="comparison-card__breakdown-row">
142+
<div className="bg-bg-default border border-border-default rounded-md text-center py-7 px-5">
143+
<div className="text-[13px] font-medium text-fg-muted uppercase tracking-[0.5px] mb-3">AI Credits-based billing (AICs)</div>
144+
<div className="text-4xl font-bold leading-[1.2] text-app-savings-fg">{formatUsd(totals.aicNetAmount)}</div>
145+
<div className="text-sm text-fg-default mt-1.5">{formatAic(totals.aicQuantity)} AICs</div>
146+
<div className="text-xs text-fg-muted mt-1">1 AIC = $0.01</div>
147+
<div className="mt-4 pt-3 border-t border-border-default w-full flex flex-col gap-1.5 text-left">
148+
<div className="flex justify-between items-center text-[13px] text-fg-default tabular-nums">
149149
<span>Gross cost</span>
150150
<span>{formatUsd(totals.aicGrossAmount)}</span>
151151
</div>
152-
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--muted">
152+
<div className="flex justify-between items-center text-[13px] text-fg-muted tabular-nums">
153153
<span>Included credits discount</span>
154154
<span>{formatUsd(Math.abs(aicDiscountAmount))}</span>
155155
</div>
156-
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--total">
156+
<div className="flex justify-between items-center text-[13px] text-fg-default tabular-nums pt-1.5 border-t border-border-default font-semibold">
157157
<span>Net cost</span>
158158
<span>{formatUsd(totals.aicNetAmount)}</span>
159159
</div>
@@ -163,72 +163,72 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
163163
</>
164164
)}
165165

166-
<div className="entitlement-banner">
167-
<div className="entitlement-banner__body">
168-
<strong className="entitlement-banner__title">Pooled entitlements are coming</strong>
169-
<p className="entitlement-banner__text">
166+
<div className="bg-bg-default border border-border-default rounded-md py-5 px-6 mt-6 flex items-center gap-5">
167+
<div className="flex-1 flex flex-col gap-1">
168+
<strong className="text-sm font-semibold text-fg-default">Pooled entitlements are coming</strong>
169+
<p className="m-0 text-[13px] text-fg-muted leading-normal">
170170
Under AI Credits-based billing, entitlements will be pooled across all licensed users in your account. No more unused capacity going to waste from idle users.
171171
</p>
172172
</div>
173173
<a
174174
href="https://github.blog/"
175-
className="entitlement-banner__link"
175+
className="text-sm font-medium text-fg-accent no-underline whitespace-nowrap hover:underline"
176176
target="_blank"
177177
rel="noopener noreferrer"
178178
>
179179
Learn more &rarr;
180180
</a>
181181
</div>
182182

183-
<div className="cost-centers-view__tables">
184-
<div className="cost-centers-view__tableControls" aria-label="Cost center detail tables">
183+
<div className="grid grid-cols-1 gap-5">
184+
<div className="flex flex-wrap border-b border-border-default" aria-label="Cost center detail tables">
185185
<button
186186
type="button"
187-
className={`cost-centers-view__tableButton ${activeTable === 'users' ? 'cost-centers-view__tableButton--active' : ''}`}
187+
className={`border-0 border-b-2 border-b-transparent -mb-px rounded-none bg-transparent text-fg-muted px-4 py-2 text-sm font-normal cursor-pointer transition-[color,border-color] duration-100 ease-in-out hover:text-fg-default focus-visible:outline-2 focus-visible:outline-fg-accent focus-visible:outline-offset-[-2px] focus-visible:rounded-sm ${activeTable === 'users' ? 'text-fg-default! font-semibold! border-b-fg-accent!' : ''}`}
188188
onClick={() => setActiveTable('users')}
189189
aria-pressed={activeTable === 'users'}
190190
>
191191
Top {MAX_DETAIL_ROWS} users
192192
</button>
193193
<button
194194
type="button"
195-
className={`cost-centers-view__tableButton ${activeTable === 'models' ? 'cost-centers-view__tableButton--active' : ''}`}
195+
className={`border-0 border-b-2 border-b-transparent -mb-px rounded-none bg-transparent text-fg-muted px-4 py-2 text-sm font-normal cursor-pointer transition-[color,border-color] duration-100 ease-in-out hover:text-fg-default focus-visible:outline-2 focus-visible:outline-fg-accent focus-visible:outline-offset-[-2px] focus-visible:rounded-sm ${activeTable === 'models' ? 'text-fg-default! font-semibold! border-b-fg-accent!' : ''}`}
196196
onClick={() => setActiveTable('models')}
197197
aria-pressed={activeTable === 'models'}
198198
>
199199
Top {MAX_DETAIL_ROWS} models
200200
</button>
201201
</div>
202202

203-
<div className="cost-centers-view__tableWrap data-table-wrap">
204-
<div className="cost-centers-view__tableTitle">
203+
<div className="bg-bg-default border border-border-default rounded-md overflow-hidden">
204+
<div className="px-4 py-3 border-b border-border-default text-xs font-bold tracking-[0.05em] uppercase text-fg-muted bg-bg-muted">
205205
{activeTable === 'users' ? `Per user (top ${MAX_DETAIL_ROWS})` : `Per model (top ${MAX_DETAIL_ROWS})`}
206206
</div>
207-
<div className="cost-centers-view__tableHint">
207+
<div className="px-4 pt-3 text-[13px] text-fg-muted">
208208
Showing the top {MAX_DETAIL_ROWS} {activeTable === 'users' ? 'users' : 'models'} by AI Credits consumed for <strong>{selectedCostCenterName}</strong>.
209209
</div>
210-
<table className="cost-centers-view__table data-table" key={`${selectedCostCenterName}-${activeTable}`}>
210+
<table className="w-full border-collapse text-[13px]" key={`${selectedCostCenterName}-${activeTable}`}>
211211
<thead>
212212
<tr>
213-
<th>{activeTable === 'users' ? 'User' : 'Model'}</th>
214-
<th className="cost-centers-view__num">PRUs</th>
215-
<th className="cost-centers-view__num">PRU Cost</th>
216-
<th className="cost-centers-view__num">AICs</th>
217-
<th className="cost-centers-view__num">AIC Cost</th>
218-
<th className="cost-centers-view__num">Difference</th>
213+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-left text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default">{activeTable === 'users' ? 'User' : 'Model'}</th>
214+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default text-right">PRUs</th>
215+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default text-right">PRU Cost</th>
216+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default text-right">AICs</th>
217+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default text-right">AIC Cost</th>
218+
<th className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-[11px] tracking-[0.05em] uppercase font-semibold text-fg-muted bg-bg-default text-right">Difference</th>
219219
</tr>
220220
</thead>
221-
<tbody>
221+
<tbody className="[&>tr:last-child>td]:border-b-0">
222222
{(activeTable === 'users' ? userRows : modelRows).map((row) => {
223223
const diff = calculateSavingsDifference(row.totals.netAmount, row.totals.aicNetAmount)
224224
return (
225225
<tr key={row.label}>
226-
<td className="cost-centers-view__name">{row.label}</td>
227-
<td className="cost-centers-view__num">{row.totals.requests.toLocaleString()}</td>
228-
<td className="cost-centers-view__num">{formatUsd(row.totals.netAmount)}</td>
229-
<td className="cost-centers-view__num">{formatAic(row.totals.aicQuantity)}</td>
230-
<td className="cost-centers-view__num">{formatUsd(row.totals.aicNetAmount)}</td>
231-
<td className={`cost-centers-view__num cost-centers-view__diff${diff > 0 ? '--positive' : diff < 0 ? '--negative' : ''}`}>
226+
<td className="px-4 py-3 border-b border-bg-muted whitespace-nowrap font-semibold text-fg-default">{row.label}</td>
227+
<td className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-right tabular-nums">{row.totals.requests.toLocaleString()}</td>
228+
<td className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-right tabular-nums">{formatUsd(row.totals.netAmount)}</td>
229+
<td className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-right tabular-nums">{formatAic(row.totals.aicQuantity)}</td>
230+
<td className="px-4 py-3 border-b border-bg-muted whitespace-nowrap text-right tabular-nums">{formatUsd(row.totals.aicNetAmount)}</td>
231+
<td className={`px-4 py-3 border-b border-bg-muted whitespace-nowrap text-right tabular-nums${diff > 0 ? ' text-app-savings-fg font-semibold' : diff < 0 ? ' text-fg-danger font-semibold' : ''}`}>
232232
{formatDifference(diff)}
233233
</td>
234234
</tr>

src/views/FaqView.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ const FAQ_ITEMS: { question: string; answer: string }[] = [
3535

3636
export function FaqView() {
3737
return (
38-
<section className="faq">
39-
<h2 className="faq__heading">Frequently Asked Questions</h2>
38+
<section className="max-w-[960px]">
39+
<h2 className="text-lg font-semibold text-fg-default mb-6">Frequently Asked Questions</h2>
4040

41-
<dl className="faq__list">
41+
<dl className="flex flex-col gap-4 m-0 p-0">
4242
{FAQ_ITEMS.map(({ question, answer }, i) => (
43-
<div key={i} className="faq__item">
44-
<dt className="faq__question">{question}</dt>
45-
<dd className="faq__answer">{answer}</dd>
43+
<div key={i} className="bg-bg-default border border-border-default rounded-lg px-6 py-5">
44+
<dt className="text-base font-semibold text-fg-default mb-3">{question}</dt>
45+
<dd className="text-sm text-fg-muted leading-relaxed m-0">{answer}</dd>
4646
</div>
4747
))}
4848
</dl>

0 commit comments

Comments
 (0)