feat: add brand color system, showtext fonts, and dark theme
R-CMD-check / R CMD check (push) Failing after 1m39s

- R/colors.R: civilytics_colors named vector (from --cv-* CSS vars on
  civilytics.com), three palettes (main/sequential/diverging),
  scale_color_civilytics() and scale_fill_civilytics() for ggplot2
- R/fonts.R: auto-loads Inter + Libre Franklin from Google Fonts via
  showtext in .onLoad(); exports civilytics_load_fonts() for manual retry
- R/theme.R: wires ggplot2 4.0 ink/paper/accent params into theme_grey()
  base, adds title_family + strip_color params; new theme_civilytics_dark()
  using navy_dark background and warm off-white text
- R/logo.R: make_logo_grob(variant) accepts "light"/"dark" to select the
  white logo for dark-background compositions
- DESCRIPTION: adds showtext, sysfonts; pins ggplot2 >= 4.0.0
- tests/testthat/test_theme.R: full test suite for colors, palettes,
  scales, both theme variants, and logo grob variants
This commit is contained in:
2026-05-17 10:36:59 -06:00
parent 2d70d9aecf
commit c93c469267
17 changed files with 996 additions and 206 deletions
+179 -12
View File
@@ -1,12 +1,179 @@
# context("Histograms")
#
# library(ggplot2)
# disp_hist_base <- function() hist(mtcars$disp)
# disp_hist_ggplot <- ggplot(mtcars, aes(disp)) + geom_histogram()
#
# test_that({
# skip("Not currently working")
# vdiffr::expect_doppelganger("Base graphics histogram", disp_hist_base)
# vdiffr::expect_doppelganger("ggplot2 histogram", disp_hist_ggplot)
#
# })
library(ggplot2)
# --- civilytics_colors -------------------------------------------------------
test_that("civilytics_colors is a named character vector of hex codes", {
expect_type(civilytics_colors, "character")
expect_named(civilytics_colors)
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", civilytics_colors)))
})
test_that("civilytics_colors contains expected brand keys", {
expected <- c("paper", "ink", "accent", "navy", "navy_dark",
"accent_dark", "paper_2", "rule")
expect_true(all(expected %in% names(civilytics_colors)))
})
test_that("civilytics_colors values match brand specification", {
expect_equal(unname(civilytics_colors["paper"]), "#FAF7F2")
expect_equal(unname(civilytics_colors["ink"]), "#0E1A2B")
expect_equal(unname(civilytics_colors["accent"]), "#C25311")
expect_equal(unname(civilytics_colors["navy_dark"]), "#1A2E4A")
expect_equal(unname(civilytics_colors["accent_dark"]),"#E07840")
})
# --- civilytics_pal ----------------------------------------------------------
test_that("civilytics_pal returns character vector of hex codes", {
result <- civilytics_pal()
expect_type(result, "character")
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", result)))
})
test_that("civilytics_pal respects n argument", {
expect_length(civilytics_pal("main", n = 3), 3)
expect_length(civilytics_pal("sequential", n = 5), 5)
})
test_that("civilytics_pal interpolates when n exceeds palette size", {
result <- civilytics_pal("main", n = 10)
expect_length(result, 10)
expect_true(all(grepl("^#[0-9A-Fa-f]{6}$", result)))
})
test_that("civilytics_pal errors on unknown palette name", {
expect_error(civilytics_pal("nope"), "'nope' is not a valid Civilytics palette")
})
test_that("civilytics_pal supports all three named palettes", {
expect_no_error(civilytics_pal("main"))
expect_no_error(civilytics_pal("sequential"))
expect_no_error(civilytics_pal("diverging"))
})
# --- scale_color/fill_civilytics ---------------------------------------------
test_that("scale_color_civilytics returns a Scale object (discrete)", {
sc <- scale_color_civilytics()
expect_s3_class(sc, "Scale")
})
test_that("scale_color_civilytics returns a Scale object (continuous)", {
sc <- scale_color_civilytics("sequential", discrete = FALSE)
expect_s3_class(sc, "Scale")
})
test_that("scale_fill_civilytics returns a Scale object (discrete)", {
sc <- scale_fill_civilytics()
expect_s3_class(sc, "Scale")
})
test_that("scale_fill_civilytics returns a Scale object (continuous)", {
sc <- scale_fill_civilytics("sequential", discrete = FALSE)
expect_s3_class(sc, "Scale")
})
test_that("scale_color_civilytics works in a ggplot", {
p <- ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
scale_color_civilytics()
expect_no_error(ggplot_build(p))
})
test_that("scale_fill_civilytics works in a ggplot", {
p <- ggplot(mpg, aes(class, fill = class)) +
geom_bar() +
scale_fill_civilytics()
expect_no_error(ggplot_build(p))
})
# --- theme_civilytics --------------------------------------------------------
test_that("theme_civilytics returns a complete ggplot2 theme", {
th <- theme_civilytics()
expect_s3_class(th, "theme")
expect_true(attr(th, "complete"))
})
test_that("theme_civilytics applies to a ggplot without error", {
p <- ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics()
expect_no_error(ggplot_build(p))
})
test_that("theme_civilytics uses brand ink color for text", {
th <- theme_civilytics()
expect_equal(th$text$colour, unname(civilytics_colors["ink"]))
})
test_that("theme_civilytics uses brand paper color for plot background", {
th <- theme_civilytics()
expect_equal(th$plot.background$fill, unname(civilytics_colors["paper"]))
})
test_that("theme_civilytics uses paper_2 for strip background by default", {
th <- theme_civilytics()
expect_equal(th$strip.background$fill, unname(civilytics_colors["paper_2"]))
})
test_that("theme_civilytics strip_color parameter is respected", {
th <- theme_civilytics(strip_color = "#FF0000")
expect_equal(th$strip.background$fill, "#FF0000")
})
test_that("theme_civilytics font_size parameter scales text elements", {
th_big <- theme_civilytics(font_size = 20)
th_sml <- theme_civilytics(font_size = 10)
expect_gt(th_big$text$size, th_sml$text$size)
})
# --- theme_civilytics_dark ---------------------------------------------------
test_that("theme_civilytics_dark returns a complete ggplot2 theme", {
th <- theme_civilytics_dark()
expect_s3_class(th, "theme")
expect_true(attr(th, "complete"))
})
test_that("theme_civilytics_dark applies to a ggplot without error", {
p <- ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics_dark()
expect_no_error(ggplot_build(p))
})
test_that("theme_civilytics_dark uses paper color as ink (light text on dark bg)", {
th <- theme_civilytics_dark()
expect_equal(th$text$colour, unname(civilytics_colors["paper"]))
})
test_that("theme_civilytics_dark uses navy_dark as background", {
th <- theme_civilytics_dark()
expect_equal(th$plot.background$fill, unname(civilytics_colors["navy_dark"]))
})
test_that("theme_civilytics_dark uses navy for strip background", {
th <- theme_civilytics_dark()
expect_equal(th$strip.background$fill, unname(civilytics_colors["navy"]))
})
# --- make_logo_grob ----------------------------------------------------------
test_that("make_logo_grob returns a gg object for light variant", {
logo <- make_logo_grob("light")
expect_s3_class(logo, "gg")
})
test_that("make_logo_grob returns a gg object for dark variant", {
logo <- make_logo_grob("dark")
expect_s3_class(logo, "gg")
})
test_that("make_logo_grob defaults to light variant", {
expect_no_error(make_logo_grob())
})
test_that("make_logo_grob errors on invalid variant", {
expect_error(make_logo_grob("purple"))
})