add type scale constants; remove scattered font size overrides

Sidebar and panel text was too small — dozens of bare fontSize:
10/11/12 values fighting the ambient DefaultTextStyle. Root font
bumped from 13 to 14. Three semantic constants replace the magic
numbers: clideFontBody (14), clideFontCaption (12), clideFontMono
(13). Widgets that render body text now inherit instead of
overriding.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-04-22 15:18:30 +02:00
co-authored by Claude
parent e290ae6dbd
commit 4f8840ccd2
16 changed files with 65 additions and 66 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ class _RootShellState extends State<_RootShell> {
return DefaultTextStyle(
style: TextStyle(
color: tokens.globalForeground,
fontSize: 13,
fontSize: 14,
fontWeight: clideUiDefaultWeight,
fontFamily: clideUiFamily,
fontFamilyFallback: clideUiFamilyFallback,
+1 -1
View File
@@ -217,7 +217,7 @@ class _ClaudePaneState extends State<ClaudePane> {
child: _error != null
? Padding(
padding: const EdgeInsets.all(16),
child: ClideText(_error!, muted: true, fontSize: 12),
child: ClideText(_error!, muted: true),
)
: ClidePtyView(
terminal: _terminal,
+12 -14
View File
@@ -57,13 +57,12 @@ class _DiffViewState extends State<DiffView> {
child: ClideText(
c.error!,
color: tokens.statusError,
fontSize: 12,
),
),
if (c.loading && c.diffs.isEmpty)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Loading…', muted: true, fontSize: 12),
child: ClideText('Loading…', muted: true),
),
if (!c.loading && c.diffs.isEmpty && c.error == null)
Padding(
@@ -73,7 +72,6 @@ class _DiffViewState extends State<DiffView> {
? 'No staged changes.'
: 'No unstaged changes.',
muted: true,
fontSize: 12,
),
),
Expanded(
@@ -119,7 +117,7 @@ class _DiffToolbar extends StatelessWidget {
onTap: controller.showStaged ? controller.toggleStaged : null,
child: ClideText(
'Unstaged',
fontSize: 12,
fontSize: clideFontCaption,
color: controller.showStaged
? tokens.globalTextMuted
: tokens.globalForeground,
@@ -135,7 +133,7 @@ class _DiffToolbar extends StatelessWidget {
onTap: controller.showStaged ? null : controller.toggleStaged,
child: ClideText(
'Staged',
fontSize: 12,
fontSize: clideFontCaption,
color: controller.showStaged
? tokens.globalForeground
: tokens.globalTextMuted,
@@ -186,15 +184,15 @@ class _FileDiff extends StatelessWidget {
Expanded(
child: ClideText(
path,
fontSize: 12,
fontSize: clideFontCaption,
color: tokens.panelHeaderForeground,
),
),
if (additions > 0)
ClideText('+$additions ', fontSize: 11,
ClideText('+$additions ', fontSize: clideFontCaption,
color: tokens.statusSuccess),
if (removals > 0)
ClideText('-$removals', fontSize: 11,
ClideText('-$removals', fontSize: clideFontCaption,
color: tokens.statusError),
],
),
@@ -202,7 +200,7 @@ class _FileDiff extends StatelessWidget {
if (meta.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 2),
child: ClideText(meta.join(' · '), fontSize: 11, muted: true),
child: ClideText(meta.join(' · '), fontSize: clideFontCaption, muted: true),
),
if (!isBinary)
for (final hunk in hunks)
@@ -241,7 +239,7 @@ class _HunkView extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 2),
child: ClideText(
header,
fontSize: 11,
fontSize: clideFontMono,
muted: true,
fontFamily: clideMonoFamily,
),
@@ -298,7 +296,7 @@ class _DiffLineRow extends StatelessWidget {
width: 36,
child: ClideText(
oldLineNo != null ? '${oldLineNo.toInt()}' : '',
fontSize: 11,
fontSize: clideFontMono,
muted: true,
fontFamily: clideMonoFamily,
textAlign: TextAlign.right,
@@ -309,7 +307,7 @@ class _DiffLineRow extends StatelessWidget {
width: 36,
child: ClideText(
newLineNo != null ? '${newLineNo.toInt()}' : '',
fontSize: 11,
fontSize: clideFontMono,
muted: true,
fontFamily: clideMonoFamily,
textAlign: TextAlign.right,
@@ -318,7 +316,7 @@ class _DiffLineRow extends StatelessWidget {
const SizedBox(width: 4),
ClideText(
prefix,
fontSize: 11,
fontSize: clideFontMono,
color: fg,
fontFamily: clideMonoFamily,
),
@@ -326,7 +324,7 @@ class _DiffLineRow extends StatelessWidget {
Expanded(
child: ClideText(
text,
fontSize: 11,
fontSize: clideFontMono,
color: fg,
fontFamily: clideMonoFamily,
maxLines: 1,
+1 -2
View File
@@ -129,7 +129,6 @@ class _EditorViewState extends State<EditorView> {
child: ClideText(
'Open a file to begin editing.',
muted: true,
fontSize: 13,
),
)
: Focus(
@@ -178,7 +177,7 @@ class _TextBody extends StatelessWidget {
focusNode: focus,
style: TextStyle(
color: foreground,
fontSize: 13,
fontSize: clideFontMono,
fontFamily: clideMonoFamily,
fontFamilyFallback: clideMonoFamilyFallback,
),
@@ -50,14 +50,14 @@ class _FileTreeViewState extends State<FileTreeView> {
if (c.error != null && c.rootPath == null) {
return Padding(
padding: const EdgeInsets.all(12),
child: ClideText(c.error!, muted: true, fontSize: 12),
child: ClideText(c.error!, muted: true),
);
}
final root = c.rootPath;
if (root == null) {
return const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Loading…', muted: true, fontSize: 12),
child: ClideText('Loading…', muted: true),
);
}
final rootName = root.split(Platform.pathSeparator).last;
@@ -256,7 +256,6 @@ class _RowState extends State<_Row> {
Expanded(
child: ClideText(
widget.label,
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
+8 -9
View File
@@ -66,20 +66,20 @@ class _GitPanelViewState extends State<GitPanelView> {
child: ClideText(
c.error!,
color: tokens.statusError,
fontSize: 11,
fontSize: clideFontCaption,
maxLines: 3,
),
),
if (c.loading && c.isClean)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Loading…', muted: true, fontSize: 12),
child: ClideText('Loading…', muted: true),
),
if (!c.loading && c.isClean && c.error == null)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Nothing to commit, working tree clean.',
muted: true, fontSize: 12),
muted: true),
),
if (c.conflicted.isNotEmpty)
_FileGroup(
@@ -162,7 +162,7 @@ class _BranchHeader extends StatelessWidget {
Expanded(
child: ClideText(
parts.join(' '),
fontSize: 12,
fontSize: clideFontCaption,
color: tokens.sidebarForeground,
),
),
@@ -217,7 +217,7 @@ class _CommitInput extends StatelessWidget {
style: TextStyle(
fontFamily: clideUiFamily,
fontWeight: clideUiDefaultWeight,
fontSize: 12,
fontSize: clideFontCaption,
color: tokens.globalForeground,
),
cursorColor: tokens.globalFocus,
@@ -286,7 +286,7 @@ class _FileGroup extends StatelessWidget {
Expanded(
child: ClideText(
'$label (${entries.length})',
fontSize: 11,
fontSize: clideFontCaption,
muted: true,
color: tokens.sidebarForeground,
),
@@ -361,14 +361,13 @@ class _GitFileRowState extends State<_GitFileRow> {
children: [
ClideText(
_stateIndicator(state),
fontSize: 11,
fontSize: clideFontCaption,
color: _stateColor(state, tokens),
),
const SizedBox(width: 6),
Expanded(
child: ClideText(
name,
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
@@ -459,7 +458,7 @@ class _SmallAction extends StatelessWidget {
cursor: SystemMouseCursors.click,
child: ClideText(
label,
fontSize: 10,
fontSize: clideFontCaption,
color: tokens.sidebarForeground,
),
),
@@ -42,7 +42,7 @@ class IpcStatusItem extends StatelessWidget {
children: [
ClideIcon(const PlugIcon(), size: 12, color: color),
const SizedBox(width: 6),
ClideText(label, fontSize: 12, color: color),
ClideText(label, fontSize: clideFontCaption, color: color),
],
),
),
+4 -7
View File
@@ -47,7 +47,6 @@ class _BacklinksViewState extends State<BacklinksView> {
child: ClideText(
'Open a file to see its links.',
muted: true,
fontSize: 12,
),
);
}
@@ -66,7 +65,6 @@ class _BacklinksViewState extends State<BacklinksView> {
horizontal: 12, vertical: 4),
child: ClideText(
c.activePath!.split('/').last,
fontSize: 12,
color: tokens.globalForeground,
),
),
@@ -77,13 +75,13 @@ class _BacklinksViewState extends State<BacklinksView> {
child: ClideText(
c.error!,
color: tokens.statusError,
fontSize: 11,
fontSize: clideFontCaption,
),
),
if (c.loading)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Loading…', muted: true, fontSize: 12),
child: ClideText('Loading…', muted: true),
),
_LinkGroup(
label: 'Backlinks',
@@ -126,14 +124,14 @@ class _LinkGroup extends StatelessWidget {
const EdgeInsets.only(left: 12, right: 8, top: 8, bottom: 2),
child: ClideText(
'$label (${links.length})',
fontSize: 11,
fontSize: clideFontCaption,
muted: true,
),
),
if (links.isEmpty)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 2),
child: ClideText('None', fontSize: 11, muted: true),
child: ClideText('None', fontSize: clideFontCaption, muted: true),
),
for (final link in links)
_LinkRow(link: link, pathKey: pathKey),
@@ -183,7 +181,6 @@ class _LinkRowState extends State<_LinkRow> {
const EdgeInsets.symmetric(horizontal: 20, vertical: 2),
child: ClideText(
display,
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: target.startsWith('http')
+11 -14
View File
@@ -68,19 +68,19 @@ class _PqlPanelViewState extends State<PqlPanelView> {
child: ClideText(
c.error!,
color: tokens.statusError,
fontSize: 11,
fontSize: clideFontCaption,
maxLines: 3,
),
),
if (c.loading && c.results.isEmpty)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Loading…', muted: true, fontSize: 12),
child: ClideText('Loading…', muted: true),
),
if (!c.loading && c.results.isEmpty && c.error == null)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('No results.', muted: true, fontSize: 12),
child: ClideText('No results.', muted: true),
),
Expanded(
child: SingleChildScrollView(
@@ -136,7 +136,7 @@ class _ViewTabs extends StatelessWidget {
cursor: SystemMouseCursors.click,
child: ClideText(
_tabLabel(v),
fontSize: 11,
fontSize: clideFontCaption,
color: controller.view == v
? tokens.globalForeground
: tokens.globalTextMuted,
@@ -187,7 +187,7 @@ class _QueryInput extends StatelessWidget {
focusNode: focus,
style: TextStyle(
fontFamily: clideMonoFamily,
fontSize: 12,
fontSize: clideFontMono,
color: tokens.globalForeground,
),
cursorColor: tokens.globalFocus,
@@ -237,7 +237,6 @@ class _FileRowState extends State<_FileRow> {
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
child: ClideText(
path,
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
@@ -267,9 +266,9 @@ class _QueryResultRow extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ClideText(name, fontSize: 12, color: tokens.sidebarForeground),
ClideText(name, color: tokens.sidebarForeground),
if (values.isNotEmpty)
ClideText(values, fontSize: 10, muted: true, maxLines: 2),
ClideText(values, fontSize: clideFontCaption, muted: true, maxLines: 2),
],
),
);
@@ -301,20 +300,19 @@ class _DecisionRow extends StatelessWidget {
children: [
SizedBox(
width: 44,
child: ClideText(id, fontSize: 11, color: idColor,
child: ClideText(id, fontSize: clideFontMono, color: idColor,
fontFamily: clideMonoFamily),
),
const SizedBox(width: 4),
Expanded(
child: ClideText(
title,
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
),
),
ClideText(domain, fontSize: 10, muted: true),
ClideText(domain, fontSize: clideFontCaption, muted: true),
],
),
);
@@ -341,7 +339,7 @@ class _TicketColumn extends StatelessWidget {
const EdgeInsets.only(left: 12, right: 8, top: 8, bottom: 2),
child: ClideText(
'$status (${tickets.length})',
fontSize: 11,
fontSize: clideFontCaption,
muted: true,
),
),
@@ -355,7 +353,7 @@ class _TicketColumn extends StatelessWidget {
width: 44,
child: ClideText(
(t as Map)['id'] as String? ?? '',
fontSize: 11,
fontSize: clideFontMono,
fontFamily: clideMonoFamily,
color: tokens.statusInfo,
),
@@ -364,7 +362,6 @@ class _TicketColumn extends StatelessWidget {
Expanded(
child: ClideText(
t['title'] as String? ?? '',
fontSize: 12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: tokens.sidebarForeground,
@@ -57,7 +57,7 @@ class _ProblemsViewState extends State<ProblemsView> {
Expanded(
child: ClideText(
'Problems (${c.problems.length})',
fontSize: 12,
fontSize: clideFontCaption,
color: tokens.sidebarForeground,
),
),
@@ -70,7 +70,7 @@ class _ProblemsViewState extends State<ProblemsView> {
cursor: SystemMouseCursors.click,
child: ClideText(
'Refresh',
fontSize: 10,
fontSize: clideFontCaption,
color: tokens.sidebarForeground,
),
),
@@ -82,7 +82,7 @@ class _ProblemsViewState extends State<ProblemsView> {
if (c.loading && c.problems.isEmpty)
const Padding(
padding: EdgeInsets.all(12),
child: ClideText('Scanning…', muted: true, fontSize: 12),
child: ClideText('Scanning…', muted: true),
),
if (!c.loading && c.problems.isEmpty)
const Padding(
@@ -90,7 +90,6 @@ class _ProblemsViewState extends State<ProblemsView> {
child: ClideText(
'No problems found.',
muted: true,
fontSize: 12,
),
),
Expanded(
@@ -130,7 +129,7 @@ class _ProblemRow extends StatelessWidget {
children: [
ClideText(
problem.source,
fontSize: 10,
fontSize: clideFontMono,
color: tokens.statusWarning,
fontFamily: clideMonoFamily,
),
@@ -138,7 +137,6 @@ class _ProblemRow extends StatelessWidget {
Expanded(
child: ClideText(
problem.message,
fontSize: 12,
color: tokens.sidebarForeground,
maxLines: 2,
),
@@ -150,7 +148,7 @@ class _ProblemRow extends StatelessWidget {
padding: const EdgeInsets.only(left: 44, top: 2),
child: ClideText(
problem.hint!,
fontSize: 10,
fontSize: clideFontMono,
muted: true,
fontFamily: clideMonoFamily,
),
@@ -168,9 +168,9 @@ class _ErrorBody extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ClideText('Terminal unavailable', fontSize: 14),
const ClideText('Terminal unavailable'),
const SizedBox(height: 4),
ClideText(message, fontSize: 12, muted: true),
ClideText(message, muted: true),
],
),
),
@@ -161,7 +161,7 @@ class _ThemeRow extends StatelessWidget {
Expanded(
child: ClideText(displayName, color: fg),
),
ClideText(name, color: tokens.globalTextMuted, fontSize: 11),
ClideText(name, color: tokens.globalTextMuted, fontSize: clideFontCaption),
],
),
),
+3 -2
View File
@@ -5,6 +5,7 @@ import 'clide_divider.dart';
import 'clide_icon.dart';
import 'clide_text.dart';
import 'icons/x.dart';
import 'typography.dart';
/// Shared chrome for any pane that sits in a tab or split: a title
/// strip at the top, an optional close button, and the pane body
@@ -146,7 +147,7 @@ class _Header extends StatelessWidget {
children: [
ClideText(
title,
fontSize: 12,
fontSize: clideFontCaption,
color: tokens.panelHeaderForeground,
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -154,7 +155,7 @@ class _Header extends StatelessWidget {
if (subtitle != null)
ClideText(
subtitle!,
fontSize: 11,
fontSize: clideFontCaption,
muted: true,
maxLines: 1,
overflow: TextOverflow.ellipsis,
+1 -1
View File
@@ -20,7 +20,7 @@ class ClidePtyView extends StatelessWidget {
this.label,
this.focusNode,
this.autofocus = false,
this.fontSize = 13,
this.fontSize = clideFontMono,
});
final Terminal terminal;
+1 -1
View File
@@ -15,7 +15,7 @@ class ClideText extends StatelessWidget {
this.data, {
super.key,
this.color,
this.fontSize = 13,
this.fontSize = 14,
this.fontFamily,
this.fontWeight,
this.muted = false,
+11
View File
@@ -46,6 +46,17 @@ const List<String> clideUiFamilyFallback = [
/// The bundled monospace family. Always resolved first.
const String clideMonoFamily = 'JetBrainsMono';
// ---------------------------------------------------------------------------
// Type scale — semantic sizes. Widgets inherit from the ambient
// DefaultTextStyle (set at the app root). Only override when the
// semantic role genuinely differs from body text. Prefer these
// constants over bare numbers so the scale stays coherent.
// ---------------------------------------------------------------------------
const double clideFontBody = 14;
const double clideFontCaption = 12;
const double clideFontMono = 13;
/// System fallback chain. Ordered by platform prevalence + quality of
/// programming-ligature / box-drawing coverage.
const List<String> clideMonoFamilyFallback = [