feat(frontend): UI/UX improvements - dark mode, accessibility, SEO - #21
Merged
Conversation
β¦me support - Update globals.css with theme-aware CSS variables - Update themes.ts with theme-aware utility functions - Replace hardcoded hex colors (#141415, #FFFFFF, #696969, etc.) with var(--color-*) in: - Skeleton.tsx: loading state components - DataInput.tsx: JSON input form - GraphContainer.tsx: graph wrapper - StatsPanel.tsx: statistics display - TokenGraph3D.tsx: 3D visualization - Tooltip.tsx: hover tooltips This enables proper light/dark theme switching across the application.
Add ARIA attributes, keyboard navigation, and focus management: TabBar.tsx: - Add role="tablist" and role="tab" semantic roles - Add aria-selected for active state - Add keyboard navigation (Arrow keys, Home/End) - Add visible focus ring styles Navigation.tsx: - Add aria-label="Main navigation" to nav element - Add aria-labels to avatar and sign-in buttons - Add aria-hidden to decorative icons GraphControls.tsx: - Add role="group" and aria-labels to control groups - Add aria-pressed for toggle buttons - Add aria-labels to selects and filter buttons BreakdownPanel.tsx: - Add role="region" to panel container - Add aria-label to close button profile/index.tsx: - Add tablist pattern to ProfileTabBar with keyboard navigation - Add aria-labels to Share and GitHub link buttons - Replace 60+ hardcoded colors with CSS variables Also includes CSS variable migration for theme support in these components.
- Remove non-functional "Danger Zone" section from settings page - Remove unused TrashIcon import - Extract client-side logic to SettingsClient.tsx for SSR metadata support - Add static SEO metadata: title "Settings - Token Usage" The account deletion feature was showing an alert saying "not yet implemented". Removing the non-functional button improves UX by not misleading users.
Add SEO metadata to all pages following Next.js 15 App Router patterns:
User Profile (/u/[username]):
- Add generateMetadata function for dynamic SEO per user
- Include OpenGraph and Twitter card metadata
- Extract client logic to ProfilePageClient.tsx
Local Page (/local):
- Add static metadata: "Local Data - Token Usage"
- Extract client logic to LocalClient.tsx
Device Page (/device):
- Add static metadata: "Device Authorization - Token Usage"
- Extract client logic to DeviceClient.tsx
The server/client split is required because Next.js 15 doesn't allow
metadata exports from Client Components ("use client").
- Replace hardcoded colors with CSS variables in leaderboard page - Update package.json and lockfile with dependencies
β¦iables Document all required environment variables for local development: - DATABASE_URL: PostgreSQL connection string - GITHUB_CLIENT_ID/SECRET: GitHub OAuth credentials - NEXT_PUBLIC_URL: Application URL for OAuth redirects This helps developers understand what's needed to run the frontend locally.
junhoyeo
marked this pull request as ready for review
December 17, 2025 11:47
haunchen
added a commit
to haunchen/tokscale
that referenced
this pull request
Aug 5, 2026
β¦ went unidentified `SessionModels::sole_model` served rows carrying neither `junhoyeo#19` nor `junhoyeo#21` whenever the file named exactly one model. That counted named ids, not models: a conversation where one row carries a display label no row ever identifies ran at least two models while naming only one, and an unlabelled row there could be either. It inherited the single named id and billed a model switch under the wrong model. Gate the fallback on every label in the file resolving to a machine id, so those rows stay `unknown` β the same rule the label path already followed, now applied to the unlabelled one. Also mark `junhoyeo#21` optional in the field table. It was present on every row observed so far, but the parser has never required it and the `sole_model` path exists precisely for rows that carry neither field.
junhoyeo
pushed a commit
that referenced
this pull request
Aug 6, 2026
β¦1051) parse_gen_metadata read the model from chatModel.#19 and fell back to the literal string "unknown", which inferred_provider_from_model cannot place, producing unpriceable antigravity/unknown rows. Antigravity CLI drops a whole group of chatModel fields (1, 2, 8, 10, 16, 19) on some continuation and tool turns, but #21 β the model display label β survives on every one, and sibling rows carry the machine id next to the identical label. Turns are now attributed by resolving that label against labels seen elsewhere in the same database. Rejected: fall back to the conversation's sole model whenever a row lacks a label | a conversation containing a model switch would bill the wrong model instead of staying unknown (cubic P1, fixed in 73d5937 by withholding the fallback when any label is unresolved) Confidence: high Scope-risk: narrow Directive: post-#1053 these rows no longer abort a submission β they are excluded silently, so a regression here is invisible rather than loud Not-tested: a database where the same display label maps to two different machine ids
junhoyeo
pushed a commit
that referenced
this pull request
Aug 18, 2026
β¦1131) * fix(antigravity-cli): resolve routing-label rows from display labels Antigravity CLI writes the generic routing label `gemini-default` as `chatModel.responseModel` (#19) whenever the router picked the model, leaving the concrete tier only in the sibling `#21` display label (e.g. "Gemini 3.5 Flash (Low)"). The parser preserved the label verbatim, so those rows were excluded from `tokscale submit` as unpriced despite carrying a tier-identifying display label. Across real databases this silently dropped ~218M tokens / $74 of Gemini usage. Resolve such rows in three steps: use a concrete `#19` as before; otherwise recover the machine id from a sibling row sharing the display label (the existing `SessionModels` mechanism); otherwise map the display label itself via a verified lookup table. A routing label is never treated as evidence of a concrete model, so it no longer poisons the `by_display` ambiguity check when a real sibling id exists. Rows that still resolve to nothing keep `gemini-default` verbatim, so the submission-time exclusion (`is_generic_routing_label` in lib.rs) continues to apply rather than guessing. Display labels are server-supplied and could be renamed or localized, so only labels verified against real user databases are mapped; anything unknown returns None and the routing label is preserved. Fixes #1116. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(antigravity-cli): map "Gemini 3.5 Flash (Low)" to gemini-3.5-flash-extra-low Align the display-label mapping with the existing alias table (`model_placeholder_m187` β `gemini-3.5-flash-extra-low` in `aliases.rs:85`) so IDE and CLI Low-tier usage resolves to the same model id. The previous value (`gemini-3.5-flash`) split the tier across two model rows. Prices are identical today, but per-tier rows would diverge β the exact scenario `aliases.rs:76-79` was written to guard against. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR delivers comprehensive frontend improvements including dark-only theme enforcement, accessibility enhancements, SEO metadata, and code quality improvements.
Changes
π Dark Mode Only
ThemeToggle.tsxcomponent (was unused).lightCSS class and all light theme variablesuseSettings.tsto only manage color palettecolorMode="night"in Primer providerβΏ Accessibility Improvements
role="tablist",role="tab",aria-selected, keyboard navigation (Arrow keys, Home/End)aria-labelto nav element and interactive buttonsaria-pressed,aria-labelto all controls and selectsrole="region"andaria-labelto close buttonrole="tooltip"π SEO Metadata
generateMetadatafunction to user profile pages for dynamic SEOProfilePageClient.tsx,SettingsClient.tsx,LocalClient.tsx,DeviceClient.tsxπ§Ή Code Quality
TrashIconimportFiles Changed
Theme (Dark Mode Enforcement)
globals.css- Removed.lightclassuseSettings.ts- Removed theme preference logicPrimerProvider.tsx- Force dark modeThemeToggle.tsx- DeletedComponents (CSS vars + Accessibility)
TabBar.tsx,Navigation.tsx,GraphControls.tsx,BreakdownPanel.tsxTooltip.tsx,Skeleton.tsx,DataInput.tsxGraphContainer.tsx,StatsPanel.tsx,TokenGraph3D.tsxprofile/index.tsx(60+ color replacements + ARIA improvements)Pages (SEO)
(main)/page.tsx,settings/page.tsx,local/page.tsx,device/page.tsxu/[username]/page.tsx(withgenerateMetadata)Testing