diff --git a/CHANGELOG.md b/CHANGELOG.md index aa52c1691..870ddce85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - The Pulls screen opens on an index of the project's pull requests across the whole screen, and a pull request opens in its place instead of beside the list. A back button over its title returns to the index as you left it; beside it, the number opens a menu of the other pull requests, and previous and next walk the index's filter. On the Files tab only the file tree sits beside the diff, which gains the width the list took. The Overview puts the description beside a column with the reviewers, checks, mergeability and the checkout the branch sits in; the tab strip ends with the pull request's size. Open in Session and Merge stay in the header, with Resolve conflicts or Fix checks beside them when the pull request needs one, and Approve, Refresh and Open on GitHub move to the ⋯ menu. The screen lines up on the sidebar's spacing, its buttons are the size of the rest of the window's, and the code a review thread is about sits in a block of its own, apart from the comments. On the index, j and k or the arrows move, Enter opens and / goes to the filter; on a pull request, Escape goes back and Alt with an arrow steps to the previous or next one. +- The bundled Dark theme gives the interface and terminal the same neutral charcoal background, removing the terminal's blue-black cast, and uses a brighter terminal and syntax palette of green, coral, amber, blue, violet and cyan. The Light theme uses darker counterparts of those colors, tuned for contrast on its light terminal background. - A session's browser is no longer closed without asking. When no pane shows it and nobody has used it for five minutes, a toast asks whether to close it: Close closes it, and Keep open, or swiping the toast away, keeps it for another five minutes. Unanswered, the toast stays up and the browser stays open, so a page left open over lunch is still there when you come back. Using the browser, or the agent using it, takes the toast down. Before, the browser was closed after five minutes away from its session, and its page, tabs and login were lost. ### Fixed diff --git a/docs/style.css b/docs/style.css index 3e9985233..96256e17c 100644 --- a/docs/style.css +++ b/docs/style.css @@ -2,7 +2,7 @@ surface, hairlines only as seams, state as fill. Values are the app's dark tokens (frontend/src/index.css). */ :root { color-scheme: dark; - --background: oklch(0.141 0.005 285.823); + --background: #101012; --canvas: color-mix(in oklab, var(--background) 65%, black); --island: oklch(0.21 0.006 285.885); --raised: oklch(0.274 0.006 286.033); diff --git a/native/cmd/lich-native/themes_test.go b/native/cmd/lich-native/themes_test.go index 11512e54b..ef14baf3a 100644 --- a/native/cmd/lich-native/themes_test.go +++ b/native/cmd/lich-native/themes_test.go @@ -57,7 +57,7 @@ func TestBundledThemesReadIntoTheIndexCSSPalettes(t *testing.T) { } } -func TestTerminalColorsFromTheTemplate(t *testing.T) { +func TestTerminalColorsFromBundledAndCustomThemes(t *testing.T) { c, err := terminalOf(bundledTheme(t, "template")) if err != nil { t.Fatal(err) @@ -65,9 +65,38 @@ func TestTerminalColorsFromTheTemplate(t *testing.T) { if c.Background != rgb(0x15111f) || c.Cursor != rgb(0xc4a7ff) || c.ANSI[1] != rgb(0xff5c8a) { t.Errorf("background %v cursor %v red %v", c.Background, c.Cursor, c.ANSI[1]) } + light, _ := terminalOf(bundledTheme(t, themeLight)) + wantLightANSI := [16]color.NRGBA{ + rgb(0x24292f), rgb(0xb33437), rgb(0x1a6b32), rgb(0x806000), + rgb(0x174ba0), rgb(0x8c3183), rgb(0x126a6f), rgb(0x4e5863), + rgb(0x3f4852), rgb(0xba3439), rgb(0x21753a), rgb(0x826100), + rgb(0x2359af), rgb(0x9b4291), rgb(0x16717a), rgb(0x5f6974), + } + if light.Background != rgb(0xe8e8ea) || light.Foreground != rgb(0x1f2328) || light.ANSI != wantLightANSI { + t.Errorf("Light terminal colors = %+v", light) + } + minimal, err := terminalOf(customTheme("minimal", "Minimal")) + if err != nil { + t.Fatal(err) + } + if minimal.ANSI != ([16]color.NRGBA{}) { + t.Errorf("custom theme without ANSI colors set some: %+v", minimal.ANSI) + } dark, _ := terminalOf(bundledTheme(t, themeDark)) - if dark.Cursor.A != 0 || dark.ANSI[1].A != 0 { - t.Errorf("a theme naming no cursor or ANSI colors set some: %+v", dark) + wantANSI := [16]color.NRGBA{ + rgb(0x151515), rgb(0xff646d), rgb(0x00cf92), rgb(0xffad33), + rgb(0x65adff), rgb(0xc992ff), rgb(0x50d6df), rgb(0xe7e7ec), + rgb(0x92929e), rgb(0xff8990), rgb(0x54e4b3), rgb(0xffc45f), + rgb(0x94c5ff), rgb(0xddb7ff), rgb(0x83e8ed), rgb(0xffffff), + } + if dark.Cursor.A != 0 { + t.Errorf("Dark cursor = %v, want libghostty's default", dark.Cursor) + } + if dark.Background != rgb(0x101012) || dark.Foreground != rgb(0xf1f1f4) { + t.Errorf("Dark terminal foreground/background = %v/%v", dark.Foreground, dark.Background) + } + if dark.ANSI != wantANSI { + t.Errorf("Dark ANSI palette = %v, want %v", dark.ANSI, wantANSI) } } @@ -268,21 +297,44 @@ func resolved(h *godemirror.HighlightStyle) map[*tags.Tag]godemirror.TagStyle { return out } -// The bundled themes write godemirror's own palettes out tag by tag, so the -// code views look as they did before themes carried syntax. -func TestBundledThemesHighlightAsGodemirrorsDefaults(t *testing.T) { - for id, want := range map[string]godemirror.Theme{themeLight: godemirror.LightTheme, themeDark: godemirror.DarkTheme} { +// Bundled syntax colors override the palette while preserving each tag's other styles. +func TestBundledSyntaxUsesPaletteColorsAndRetainsStyles(t *testing.T) { + for id, baseline := range map[string]godemirror.Theme{themeLight: godemirror.LightTheme, themeDark: godemirror.DarkTheme} { e, err := readTheme(bundledTheme(t, id)) if err != nil { t.Fatal(err) } - got, exp := resolved(e.code.Highlight), resolved(want.Highlight) - if len(got) != len(exp) { - t.Fatalf("%s: %d tags styled, godemirror styles %d", id, len(got), len(exp)) + got := resolved(e.code.Highlight) + want := resolved(baseline.Highlight) + if len(got) != len(want) { + t.Fatalf("%s: %d tags styled, want %d", id, len(got), len(want)) } - for tag, style := range exp { - if !reflect.DeepEqual(got[tag], style) { - t.Errorf("%s: %s = %+v, want %+v", id, tag, got[tag], style) + for tag, style := range want { + actual, ok := got[tag] + if !ok { + t.Errorf("%s: tag %s is missing", id, tag) + continue + } + actual.Color = style.Color + if !reflect.DeepEqual(actual, style) { + t.Errorf("%s: %s style = %+v, want non-color styles %+v", id, tag, actual, style) + } + } + samples := map[string]map[string]color.NRGBA{ + themeDark: { + "keyword": rgb(0xc992ff), "string": rgb(0x00cf92), "function(variableName)": rgb(0x65adff), + }, + themeLight: { + "keyword": rgb(0x8c3183), "string": rgb(0x1a6b32), "function(variableName)": rgb(0x174ba0), + }, + } + for name, wantColor := range samples[id] { + tag, err := tags.Parse(name) + if err != nil { + t.Fatal(err) + } + if got[tag].Color != wantColor { + t.Errorf("%s: %s color = %v, want %v", id, name, got[tag].Color, wantColor) } } } diff --git a/native/lichdiff/buttons.go b/native/lichdiff/buttons.go index e578ac22a..458d51493 100644 --- a/native/lichdiff/buttons.go +++ b/native/lichdiff/buttons.go @@ -27,7 +27,7 @@ var ( foreground = color.NRGBA{R: 0xfa, G: 0xfa, B: 0xfa, A: 0xff} mutedForeground = color.NRGBA{R: 0x9f, G: 0x9f, B: 0xa9, A: 0xff} accent = color.NRGBA{R: 0x27, G: 0x27, B: 0x2a, A: 0xff} - background = color.NRGBA{R: 0x09, G: 0x09, B: 0x0b, A: 0xff} + background = color.NRGBA{R: 0x10, G: 0x10, B: 0x12, A: 0xff} border = color.NRGBA{R: 0x22, G: 0x22, B: 0x24, A: 0xff} ) diff --git a/native/ui/checkbox_test.go b/native/ui/checkbox_test.go index 435253a59..24eb4f454 100644 --- a/native/ui/checkbox_test.go +++ b/native/ui/checkbox_test.go @@ -81,9 +81,8 @@ func TestCheckboxCheckedFillsWithPrimary(t *testing.T) { if img := draw(true); !toggleIs(img, inside, th.Primary) { t.Errorf("checked: pixel %v, want primary %v", img.RGBAAt(inside.X, inside.Y), th.Primary) } - // input/30 (white at 15% x 30%) over the page, composited in sRGB as the - // browser does: #09090b + 4.5% of the way to white. - if img, want := draw(false), (color.NRGBA{R: 20, G: 20, B: 22, A: 255}); !toggleIs(img, inside, want) { + // input/30 (white at 15% x 30%) over #101012, composited in sRGB. + if img, want := draw(false), (color.NRGBA{R: 26, G: 26, B: 28, A: 255}); !toggleIs(img, inside, want) { t.Errorf("unchecked: pixel %v, want input/30 over the page %v", img.RGBAAt(inside.X, inside.Y), want) } } @@ -95,7 +94,7 @@ func TestCheckboxDisabledFadesOntoThePage(t *testing.T) { cb := th.Checkbox(&widget.Bool{Value: true}) cb.Disabled = true img := toggleRender(t, image.Pt(16, 16), time.Time{}, cb.Layout) - if want := (color.NRGBA{R: 119, G: 119, B: 121, A: 255}); !toggleIs(img, image.Pt(3, 13), want) { + if want := (color.NRGBA{R: 122, G: 122, B: 124, A: 255}); !toggleIs(img, image.Pt(3, 13), want) { t.Errorf("disabled checked: pixel %v, want primary at 50%% over the page %v", img.RGBAAt(3, 13), want) } } diff --git a/native/ui/input_test.go b/native/ui/input_test.go index ac91334aa..8088884f9 100644 --- a/native/ui/input_test.go +++ b/native/ui/input_test.go @@ -179,7 +179,7 @@ func TestInputFocusRingDrawsOnlyWhenFocused(t *testing.T) { } } -// The box of an input over the page (#09090b), as the browser composites it: +// The box of an input over the page (#101012), as the browser composites it: // bg-input/30 for the fill, border-input over the fill, ring-ring/50 over the // page. Gio would blend each about twice as bright. func TestInputBoxPaintsTheBrowsersColors(t *testing.T) { @@ -188,17 +188,17 @@ func TestInputBoxPaintsTheBrowsersColors(t *testing.T) { rig := newInputRig(t, 160, 36, in.Layout) img := rig.frame() at := func(x, y int) image.Point { return image.Pt(rig.margin+x, rig.margin+y) } - if want := (color.NRGBA{R: 20, G: 20, B: 22, A: 255}); !toggleIs(img, at(4, 18), want) { + if want := (color.NRGBA{R: 26, G: 26, B: 28, A: 255}); !toggleIs(img, at(4, 18), want) { t.Errorf("fill %v, want input/30 over the page %v", img.RGBAAt(at(4, 18).X, at(4, 18).Y), want) } - if want := (color.NRGBA{R: 55, G: 55, B: 57, A: 255}); !toggleIs(img, at(80, 0), want) { + if want := (color.NRGBA{R: 60, G: 60, B: 62, A: 255}); !toggleIs(img, at(80, 0), want) { t.Errorf("border %v, want input over the fill %v", img.RGBAAt(at(80, 0).X, at(80, 0).Y), want) } rig.router.Source().Execute(key.FocusCmd{Tag: ed}) rig.frame() img = rig.frame() - if want := (color.NRGBA{R: 61, G: 61, B: 66, A: 255}); !toggleIs(img, at(-2, 18), want) { + if want := (color.NRGBA{R: 64, G: 64, B: 70, A: 255}); !toggleIs(img, at(-2, 18), want) { t.Errorf("focus ring %v, want ring/50 over the page %v", img.RGBAAt(at(-2, 18).X, at(-2, 18).Y), want) } if want := th.Ring; !toggleIs(img, at(80, 0), want) { @@ -224,7 +224,7 @@ func TestBareInputDrawsNoBox(t *testing.T) { } } -// disabled:opacity-50 fades the finished box: the fill (#14141 6) at half over +// disabled:opacity-50 fades the finished box: the fill (#1a1a1c) at half over // the page. func TestInputDisabledFadesOntoThePage(t *testing.T) { th := testTheme() @@ -232,7 +232,7 @@ func TestInputDisabledFadesOntoThePage(t *testing.T) { in.Disabled = true rig := newInputRig(t, 160, 36, in.Layout) p := image.Pt(rig.margin+4, rig.margin+18) - if img, want := rig.frame(), (color.NRGBA{R: 14, G: 14, B: 16, A: 255}); !toggleIs(img, p, want) { + if img, want := rig.frame(), (color.NRGBA{R: 21, G: 21, B: 23, A: 255}); !toggleIs(img, p, want) { t.Errorf("fill %v, want input/30 at half over the page %v", img.RGBAAt(p.X, p.Y), want) } } @@ -241,11 +241,11 @@ func TestInputDisabledFadesOntoThePage(t *testing.T) { func TestInputGroupInnerDrawsOnTheFill(t *testing.T) { th := testTheme() g := th.InputGroup(new(widget.Editor), "Filter") - if want := (color.NRGBA{R: 20, G: 20, B: 22, A: 255}); !near2(g.Inner().Surface, want) { + if want := (color.NRGBA{R: 26, G: 26, B: 28, A: 255}); !near2(g.Inner().Surface, want) { t.Errorf("surface %v, want input/30 over the page %v", g.Inner().Surface, want) } g.Disabled = true - if want := (color.NRGBA{R: 14, G: 14, B: 16, A: 255}); !near2(g.Inner().Surface, want) { + if want := (color.NRGBA{R: 21, G: 21, B: 23, A: 255}); !near2(g.Inner().Surface, want) { t.Errorf("disabled surface %v, want the fill at half over the page %v", g.Inner().Surface, want) } } diff --git a/native/ui/label_test.go b/native/ui/label_test.go index 6d74d7cf1..ec50d35e4 100644 --- a/native/ui/label_test.go +++ b/native/ui/label_test.go @@ -52,12 +52,12 @@ func labelInk(t *testing.T, l FormLabelStyle) color.RGBA { return ink } -// opacity-50 over the page: foreground (#fafafa) halfway to #09090b. +// opacity-50 over the page: foreground (#fafafa) halfway to #101012. func TestLabelDisabledIsHalfOpacity(t *testing.T) { th := testTheme() on, off := th.Label("Subject"), th.Label("Subject") off.Disabled = true - wantOn, wantOff := color.RGBA{R: 250, G: 250, B: 250, A: 255}, color.RGBA{R: 130, G: 130, B: 131, A: 255} + wantOn, wantOff := color.RGBA{R: 250, G: 250, B: 250, A: 255}, color.RGBA{R: 133, G: 133, B: 134, A: 255} within := func(a, b color.RGBA) bool { d := func(x, y uint8) bool { return int(x)-int(y) <= 2 && int(y)-int(x) <= 2 } return d(a.R, b.R) && d(a.G, b.G) && d(a.B, b.B) && a.A == b.A diff --git a/native/ui/skeleton_test.go b/native/ui/skeleton_test.go index 3bf6dbe74..942d262b5 100644 --- a/native/ui/skeleton_test.go +++ b/native/ui/skeleton_test.go @@ -39,11 +39,11 @@ func skeletonAt(t *testing.T, at time.Duration) color.NRGBA { } // animate-pulse: full opacity at both ends of its 2s, half of it at 1s. The -// browser lays bg-foreground/20 (#fafafa at 20%) over the page (#09090b) in -// sRGB: #39393b, and half of that opacity, #212123. +// browser lays bg-foreground/20 (#fafafa at 20%) over the page (#101012) in +// sRGB: #3f3f40, and half of that opacity, #272729. func TestSkeletonPulsesBetweenFullAndHalf(t *testing.T) { full, half, again := skeletonAt(t, 0), skeletonAt(t, time.Second), skeletonAt(t, 2*time.Second) - wantFull, wantHalf := color.NRGBA{R: 57, G: 57, B: 59, A: 255}, color.NRGBA{R: 33, G: 33, B: 35, A: 255} + wantFull, wantHalf := color.NRGBA{R: 63, G: 63, B: 64, A: 255}, color.NRGBA{R: 39, G: 39, B: 41, A: 255} close := func(a, b color.NRGBA) bool { d := func(x, y uint8) bool { return int(x)-int(y) <= 1 && int(y)-int(x) <= 1 } return d(a.R, b.R) && d(a.G, b.G) && d(a.B, b.B) && a.A == b.A diff --git a/native/ui/switch_test.go b/native/ui/switch_test.go index f1e792a37..265007cbd 100644 --- a/native/ui/switch_test.go +++ b/native/ui/switch_test.go @@ -103,7 +103,7 @@ func TestSwitchDisabledThumbSitsOnThePageNotTheTrack(t *testing.T) { s := testTheme().Switch(state) s.Disabled = true img := toggleRender(t, image.Pt(32, 18), time.Unix(1000, 0), s.Layout) - thumb, track := color.NRGBA{R: 17, G: 17, B: 19, A: 255}, color.NRGBA{R: 119, G: 119, B: 121, A: 255} + thumb, track := color.NRGBA{R: 20, G: 20, B: 22, A: 255}, color.NRGBA{R: 122, G: 122, B: 124, A: 255} if !toggleIs(img, image.Pt(23, 9), thumb) { t.Errorf("thumb pixel %v, want primary-foreground at half over the page %v", img.RGBAAt(23, 9), thumb) } @@ -115,7 +115,7 @@ func TestSwitchDisabledThumbSitsOnThePageNotTheTrack(t *testing.T) { // dark:data-unchecked:bg-input/80 is white at 12% over the page. func TestSwitchOffTrackIsInputOverThePage(t *testing.T) { img := toggleRender(t, image.Pt(32, 18), time.Unix(1000, 0), testTheme().Switch(new(SwitchState)).Layout) - if want := (color.NRGBA{R: 38, G: 38, B: 40, A: 255}); !toggleIs(img, image.Pt(28, 9), want) { + if want := (color.NRGBA{R: 44, G: 44, B: 46, A: 255}); !toggleIs(img, image.Pt(28, 9), want) { t.Errorf("off track pixel %v, want input/80 over the page %v", img.RGBAAt(28, 9), want) } } diff --git a/native/ui/theme.go b/native/ui/theme.go index c6f02da9e..5b3e9e2bb 100644 --- a/native/ui/theme.go +++ b/native/ui/theme.go @@ -28,10 +28,10 @@ type Palette struct { // Dark is the dark theme (themes/dark.json). var Dark = Palette{ - Background: OKLCH(0.141, 0.005, 285.823, 1), + Background: color.NRGBA{R: 0x10, G: 0x10, B: 0x12, A: 0xff}, Foreground: OKLCH(0.985, 0, 0, 1), // color-mix(in oklab, var(--background) 65%, black). - Canvas: MixOKLab(OKLCH(0.141, 0.005, 285.823, 1), color.NRGBA{A: 255}, 0.35), + Canvas: MixOKLab(color.NRGBA{R: 0x10, G: 0x10, B: 0x12, A: 0xff}, color.NRGBA{A: 255}, 0.35), Card: OKLCH(0.21, 0.006, 285.885, 1), CardForeground: OKLCH(0.985, 0, 0, 1), Popover: OKLCH(0.21, 0.006, 285.885, 1), diff --git a/native/ui/toggle_group_test.go b/native/ui/toggle_group_test.go index ce658f6e5..d880f3d82 100644 --- a/native/ui/toggle_group_test.go +++ b/native/ui/toggle_group_test.go @@ -49,7 +49,7 @@ func TestToggleGroupTrackBorderIsBorderOverThePage(t *testing.T) { group := testTheme().ToggleGroup(new(widget.Enum), toggleGroupItems...) size := layoutAt(group.Layout, 0, 500).Size img := toggleRender(t, size, time.Time{}, group.Layout) - if want := (color.NRGBA{R: 33, G: 33, B: 35, A: 255}); !toggleIs(img, image.Pt(size.X/2, 0), want) { + if want := (color.NRGBA{R: 40, G: 40, B: 42, A: 255}); !toggleIs(img, image.Pt(size.X/2, 0), want) { t.Errorf("top edge %v, want border over the page %v", img.RGBAAt(size.X/2, 0), want) } } diff --git a/native/ui/toggle_test.go b/native/ui/toggle_test.go index 984a0900d..c3266b2b1 100644 --- a/native/ui/toggle_test.go +++ b/native/ui/toggle_test.go @@ -174,9 +174,9 @@ func TestTogglePressedIsAccentFill(t *testing.T) { if img := draw(false, nil); img.RGBAAt(3, 18).A != 0 { t.Errorf("unpressed: pixel %v, want transparent", img.RGBAAt(3, 18)) } - // opacity-50 over the page: accent (#27272a) halfway to #09090b. + // opacity-50 over the page: accent (#27272a) halfway to #101012. disabled := draw(true, func(tg *ToggleStyle) { tg.Disabled = true }) - if want := (color.NRGBA{R: 24, G: 24, B: 27, A: 255}); !toggleIs(disabled, image.Pt(3, 18), want) { + if want := (color.NRGBA{R: 27, G: 27, B: 30, A: 255}); !toggleIs(disabled, image.Pt(3, 18), want) { t.Errorf("disabled pressed: pixel %v, want accent at half over the page %v", disabled.RGBAAt(3, 18), want) } } @@ -189,7 +189,7 @@ func TestToggleOutlineHasBorderDefaultHasNone(t *testing.T) { return toggleRender(t, image.Pt(80, 36), time.Time{}, tg.Layout).RGBAAt(40, 0) } // border-input is white at 15% over the page. - if p, want := edge(ToggleVariantOutline), (color.NRGBA{R: 45, G: 45, B: 47, A: 255}); !near2(color.NRGBA(p), want) { + if p, want := edge(ToggleVariantOutline), (color.NRGBA{R: 52, G: 52, B: 53, A: 255}); !near2(color.NRGBA(p), want) { t.Errorf("outline: top edge %v, want input over the page %v", p, want) } if p := edge(ToggleVariantDefault); p.A != 0 { diff --git a/native/ui/ui_test.go b/native/ui/ui_test.go index 3365c775b..82f67cb6d 100644 --- a/native/ui/ui_test.go +++ b/native/ui/ui_test.go @@ -93,7 +93,7 @@ func TestButtonMinimumWidthBelowMaximumIsTheWidth(t *testing.T) { } } -// What the browser paints for each translucent class, over the page (#09090b), +// What the browser paints for each translucent class, over the page (#101012), // composited in sRGB; Gio would blend each about twice as bright. func TestButtonVariantFillsAreTheBrowsersColors(t *testing.T) { th := testTheme() @@ -104,12 +104,12 @@ func TestButtonVariantFillsAreTheBrowsersColors(t *testing.T) { disabled bool want color.NRGBA }{ - {"outline dark:bg-input/30", VariantOutline, false, false, color.NRGBA{R: 20, G: 20, B: 22, A: 255}}, - {"outline dark:hover:bg-input/50", VariantOutline, true, false, color.NRGBA{R: 27, G: 27, B: 29, A: 255}}, - {"ghost dark:hover:bg-muted/50", VariantGhost, true, false, color.NRGBA{R: 24, G: 24, B: 27, A: 255}}, - {"destructive dark:bg-destructive/20", VariantDestructive, false, false, color.NRGBA{R: 58, G: 27, B: 29, A: 255}}, + {"outline dark:bg-input/30", VariantOutline, false, false, color.NRGBA{R: 26, G: 26, B: 28, A: 255}}, + {"outline dark:hover:bg-input/50", VariantOutline, true, false, color.NRGBA{R: 34, G: 34, B: 36, A: 255}}, + {"ghost dark:hover:bg-muted/50", VariantGhost, true, false, color.NRGBA{R: 27, G: 27, B: 30, A: 255}}, + {"destructive dark:bg-destructive/20", VariantDestructive, false, false, color.NRGBA{R: 64, G: 33, B: 35, A: 255}}, {"default hover:bg-primary/80", VariantDefault, true, false, color.NRGBA{R: 184, G: 184, B: 187, A: 255}}, - {"default disabled:opacity-50", VariantDefault, false, true, color.NRGBA{R: 119, G: 119, B: 121, A: 255}}, + {"default disabled:opacity-50", VariantDefault, false, true, color.NRGBA{R: 122, G: 122, B: 124, A: 255}}, } for _, tc := range cases { b := th.Button(new(widget.Clickable), "Shell") @@ -127,7 +127,7 @@ func TestButtonOutlineBorderIsInputOverThePage(t *testing.T) { b := testTheme().Button(new(widget.Clickable), "Shell") b.Variant = VariantOutline img := toggleRender(t, image.Pt(80, 36), time.Time{}, func(gtx C) D { return b.draw(gtx, false) }) - want := color.NRGBA{R: 45, G: 45, B: 47, A: 255} + want := color.NRGBA{R: 52, G: 52, B: 53, A: 255} if !toggleIs(img, image.Pt(20, 0), want) { t.Errorf("top row %v, want input over the page %v", img.RGBAAt(20, 0), want) } @@ -139,7 +139,7 @@ func TestButtonOutlineBorderIsInputOverThePage(t *testing.T) { func TestSeparatorIsBorderOverThePage(t *testing.T) { th := testTheme() img := toggleRender(t, image.Pt(40, 4), time.Time{}, th.Separator) - if want := (color.NRGBA{R: 33, G: 33, B: 35, A: 255}); !toggleIs(img, image.Pt(20, 0), want) { + if want := (color.NRGBA{R: 40, G: 40, B: 42, A: 255}); !toggleIs(img, image.Pt(20, 0), want) { t.Errorf("pixel %v, want border (white at 10%%) over the page %v", img.RGBAAt(20, 0), want) } } @@ -147,10 +147,10 @@ func TestSeparatorIsBorderOverThePage(t *testing.T) { // The thumb is currentColor at 25%, 40% hovered. func TestScrollAreaThumbIsForegroundOverThePage(t *testing.T) { list := testTheme().ScrollArea(new(widget.List)) - if want := (color.NRGBA{R: 69, G: 69, B: 71, A: 255}); !near2(list.Indicator.Color, want) { + if want := (color.NRGBA{R: 74, G: 74, B: 75, A: 255}); !near2(list.Indicator.Color, want) { t.Errorf("thumb %v, want foreground at 25%% over the page %v", list.Indicator.Color, want) } - if want := (color.NRGBA{R: 105, G: 105, B: 107, A: 255}); !near2(list.Indicator.HoverColor, want) { + if want := (color.NRGBA{R: 110, G: 110, B: 111, A: 255}); !near2(list.Indicator.HoverColor, want) { t.Errorf("hovered thumb %v, want foreground at 40%% over the page %v", list.Indicator.HoverColor, want) } } diff --git a/themes/dark.json b/themes/dark.json index f79f3cba5..1c1a61ce4 100644 --- a/themes/dark.json +++ b/themes/dark.json @@ -5,7 +5,7 @@ "origin": "bundled", "pair": "light", "app": { - "background": "oklch(0.141 0.005 285.823)", + "background": "#101012", "foreground": "oklch(0.985 0 0)", "card": "oklch(0.21 0.006 285.885)", "card-foreground": "oklch(0.985 0 0)", @@ -40,42 +40,58 @@ "sidebar-ring": "oklch(0.552 0.016 285.938)" }, "terminal": { - "background": "#06070f", - "foreground": "#e5e7eb" + "background": "#101012", + "foreground": "#f1f1f4", + "black": "#151515", + "red": "#ff646d", + "green": "#00cf92", + "yellow": "#ffad33", + "blue": "#65adff", + "magenta": "#c992ff", + "cyan": "#50d6df", + "white": "#e7e7ec", + "brightBlack": "#92929e", + "brightRed": "#ff8990", + "brightGreen": "#54e4b3", + "brightYellow": "#ffc45f", + "brightBlue": "#94c5ff", + "brightMagenta": "#ddb7ff", + "brightCyan": "#83e8ed", + "brightWhite": "#ffffff" }, "syntax": { - "keyword": "#c396f5", - "string": "#82cb92", - "regexp": "#82cb92", - "escape": "#82cb92", - "special(string)": "#82cb92", + "keyword": "#c992ff", + "string": "#00cf92", + "regexp": "#00cf92", + "escape": "#00cf92", + "special(string)": "#00cf92", "comment": { - "color": "#9f9fa9", + "color": "#92929e", "italic": true }, "processingInstruction": { - "color": "#9f9fa9", + "color": "#92929e", "italic": true }, - "literal": "#eca760", - "number": "#eca760", - "bool": "#eca760", - "null": "#eca760", - "atom": "#eca760", - "typeName": "#71d0d5", - "className": "#71d0d5", - "namespace": "#71d0d5", - "standard(variableName)": "#71d0d5", - "propertyName": "#82b1ed", - "tagName": "#82b1ed", - "function(variableName)": "#82b1ed", + "literal": "#ffad33", + "number": "#ffad33", + "bool": "#ffad33", + "null": "#ffad33", + "atom": "#ffad33", + "typeName": "#50d6df", + "className": "#50d6df", + "namespace": "#50d6df", + "standard(variableName)": "#50d6df", + "propertyName": "#65adff", + "tagName": "#65adff", + "function(variableName)": "#65adff", "definition(local(variableName))": { "italic": true }, - "punctuation": "#9f9fa9", - "operator": "#9f9fa9", - "operatorKeyword": "#9f9fa9", - "invalid": "#ff6467", + "punctuation": "#92929e", + "operator": "#92929e", + "operatorKeyword": "#92929e", + "invalid": "#ff646d", "strong": { "bold": true }, diff --git a/themes/light.json b/themes/light.json index 78935e0a1..eb2e05d02 100644 --- a/themes/light.json +++ b/themes/light.json @@ -41,41 +41,57 @@ }, "terminal": { "background": "#e8e8ea", - "foreground": "#1f2328" + "foreground": "#1f2328", + "black": "#24292f", + "red": "#b33437", + "green": "#1a6b32", + "yellow": "#806000", + "blue": "#174ba0", + "magenta": "#8c3183", + "cyan": "#126a6f", + "white": "#4e5863", + "brightBlack": "#3f4852", + "brightRed": "#ba3439", + "brightGreen": "#21753a", + "brightYellow": "#826100", + "brightBlue": "#2359af", + "brightMagenta": "#9b4291", + "brightCyan": "#16717a", + "brightWhite": "#5f6974" }, "syntax": { - "keyword": "#6c329f", - "string": "#206b38", - "regexp": "#206b38", - "escape": "#206b38", - "special(string)": "#206b38", + "keyword": "#8c3183", + "string": "#1a6b32", + "regexp": "#1a6b32", + "escape": "#1a6b32", + "special(string)": "#1a6b32", "comment": { - "color": "#64636e", + "color": "#59636e", "italic": true }, "processingInstruction": { - "color": "#64636e", + "color": "#59636e", "italic": true }, - "literal": "#9d5300", - "number": "#9d5300", - "bool": "#9d5300", - "null": "#9d5300", - "atom": "#9d5300", - "typeName": "#006e74", - "className": "#006e74", - "namespace": "#006e74", - "standard(variableName)": "#006e74", - "propertyName": "#17559b", - "tagName": "#17559b", - "function(variableName)": "#17559b", + "literal": "#806000", + "number": "#806000", + "bool": "#806000", + "null": "#806000", + "atom": "#806000", + "typeName": "#126a6f", + "className": "#126a6f", + "namespace": "#126a6f", + "standard(variableName)": "#126a6f", + "propertyName": "#174ba0", + "tagName": "#174ba0", + "function(variableName)": "#174ba0", "definition(local(variableName))": { "italic": true }, - "punctuation": "#64636e", - "operator": "#64636e", - "operatorKeyword": "#64636e", - "invalid": "#e7000b", + "punctuation": "#59636e", + "operator": "#59636e", + "operatorKeyword": "#59636e", + "invalid": "#b33437", "strong": { "bold": true },