bundle Josefin Sans as the default UI face at weight 300

Vendor the JosefinSans variable font (upright + italic, weight range
100-700), OFL licensed. _AppRoot installs it as the ambient
DefaultTextStyle at weight w300 (Light); ClideText inherits rather
than re-specifying the family, so Alchemist's Ahem injection keeps
goldens deterministic per D-024 while production renders the
intended face.

typography.dart gains clideUiFamily + clideUiFamilyFallback
alongside the existing mono constants; .gitignore learns about
Alchemist's failures/ diff output dir so local re-runs don't leak
into `git status`.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-04-22 08:18:15 +02:00
co-authored by Claude
parent 7bdeb9ab24
commit c1ad33f1b0
8 changed files with 172 additions and 21 deletions
+5
View File
@@ -47,6 +47,11 @@ tools/ui/.serve.pid
coverage.*
/tmp/
# Alchemist golden-test failure artefacts (diff images written when a
# pixel-compare fails locally; the committed fixtures live under
# app/test/goldens/goldens/{ci,linux}/).
app/test/goldens/failures/
# -- pql per-repo state (clide dogfoods against itself; pql's index lands
# here when running queries locally). `pql.db` is also where the
# `tools/scripts/plan` stopgap writes decisions + tickets (D-040).
+93
View File
@@ -0,0 +1,93 @@
Copyright 2010 The Josefin Sans Project Authors (https://github.com/ThomasJockin/JosefinSansFont-master), with Reserved Font Name "Josefin Sans".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+3 -6
View File
@@ -70,12 +70,9 @@ class _RootShellState extends State<_RootShell> {
style: TextStyle(
color: tokens.globalForeground,
fontSize: 13,
fontFamilyFallback: const [
'Inter',
'Helvetica',
'Arial',
'sans-serif',
],
fontWeight: clideUiDefaultWeight,
fontFamily: clideUiFamily,
fontFamilyFallback: clideUiFamilyFallback,
),
child: KeyboardListener(
focusNode: _keyFocus,
+15 -4
View File
@@ -1,14 +1,22 @@
import 'package:clide_app/kernel/src/theme/controller.dart';
import 'package:clide_app/widgets/src/typography.dart';
import 'package:flutter/widgets.dart';
/// Theme-aware Text. Defaults pull from the global foreground token.
/// Theme-aware Text. Defaults pull from the global foreground token
/// and [clideUiDefaultWeight].
///
/// The UI font family is deliberately **not** set on this widget — it
/// inherits from the ambient `DefaultTextStyle` which `_AppRoot`
/// provides ([clideUiFamily] in real runs). Goldens rely on Alchemist
/// injecting Ahem for deterministic metrics; hard-coding a family here
/// would override that and break pixel determinism per D-024.
class ClideText extends StatelessWidget {
const ClideText(
this.data, {
super.key,
this.color,
this.fontSize = 13,
this.fontWeight = FontWeight.w400,
this.fontWeight,
this.muted = false,
this.maxLines,
this.overflow,
@@ -18,7 +26,7 @@ class ClideText extends StatelessWidget {
final String data;
final Color? color;
final double fontSize;
final FontWeight fontWeight;
final FontWeight? fontWeight;
final bool muted;
final int? maxLines;
final TextOverflow? overflow;
@@ -37,8 +45,11 @@ class ClideText extends StatelessWidget {
style: TextStyle(
color: resolved,
fontSize: fontSize,
// Null means inherit from the ambient DefaultTextStyle —
// _AppRoot installs clideUiDefaultWeight there; goldens get
// whatever Alchemist injects. Passing an explicit weight (e.g.
// FontWeight.bold) still wins.
fontWeight: fontWeight,
fontFamilyFallback: const ['Inter', 'Helvetica', 'Arial', 'sans-serif'],
),
);
}
+42 -7
View File
@@ -1,12 +1,48 @@
/// Typography constants shared across widgets.
///
/// Terminal panes, diff views, and any other monospace surface should
/// import from here rather than hardcoding a family. The fallback chain
/// exists for web builds + platforms where the bundled `JetBrainsMono`
/// Two bundled families:
///
/// - [clideUiFamily] — Josefin Sans, the application-wide UI face.
/// Shipped as a variable font (weights 100-700) + italic companion;
/// default weight is [clideUiDefaultWeight] (Light / `w300`).
/// - [clideMonoFamily] — JetBrains Mono, for terminal panes, diff
/// views, code editors, and any other monospace surface.
///
/// Fallback chains exist for web builds + harnesses where the bundled
/// asset isn't picked up (rare, but possible during `flutter test` if
/// assets aren't declared in the harness).
/// asset fonts aren't declared in the harness).
library;
import 'package:flutter/widgets.dart' show FontWeight;
// ---------------------------------------------------------------------------
// UI face — Josefin Sans
// ---------------------------------------------------------------------------
/// The bundled application UI family. Always resolved first.
const String clideUiFamily = 'JosefinSans';
/// Default weight for UI text. Josefin Sans reads well at Light; the
/// rest of the design adjusts contrast and size to stay legible.
const FontWeight clideUiDefaultWeight = FontWeight.w300;
/// System fallback chain for the UI face. Sans-serif humanist faces
/// that sit close to Josefin's proportions, ordered by platform.
const List<String> clideUiFamilyFallback = [
// User system install of Josefin, if any.
'Josefin Sans',
// Platform humanist sans defaults.
'Inter',
'Helvetica Neue',
'Helvetica',
'Arial',
'sans-serif',
];
// ---------------------------------------------------------------------------
// Monospace face — JetBrains Mono
// ---------------------------------------------------------------------------
/// The bundled monospace family. Always resolved first.
const String clideMonoFamily = 'JetBrainsMono';
@@ -17,9 +53,8 @@ const List<String> clideMonoFamilyFallback = [
'SF Mono',
'Menlo',
'Monaco',
// Linux
'JetBrains Mono', // if the user has it system-installed under the
// canonical PostScript name
// Linux — user system install under the canonical PostScript name
'JetBrains Mono',
'Fira Code',
'Hack',
'DejaVu Sans Mono',
+14 -4
View File
@@ -54,11 +54,21 @@ flutter:
- lib/kernel/src/theme/themes/
- lib/kernel/src/i18n/catalog/
# JetBrains Mono — bundled so terminal panes render consistently
# regardless of what the user has system-installed. OFL-licensed;
# see assets/fonts/jetbrains_mono/OFL.txt. Thin/Light/Medium/
# ExtraBold weights can be added later if a theme needs them.
# Bundled fonts. OFL-licensed; license files live alongside each.
#
# JosefinSans — UI default. Variable font covers weights 100-700
# plus an italic axis companion; we default to Light (300) per the
# project's aesthetic direction.
#
# JetBrainsMono — terminal / code surfaces. Static weights keep
# rendering predictable across xterm.dart, goldens, and CI.
fonts:
- family: JosefinSans
fonts:
- asset: assets/fonts/josefin_sans/JosefinSans-VariableFont.ttf
- asset: assets/fonts/josefin_sans/JosefinSans-Italic-VariableFont.ttf
style: italic
- family: JetBrainsMono
fonts:
- asset: assets/fonts/jetbrains_mono/JetBrainsMono-Regular.ttf