Author SHA1 Message Date
kodor 967e7e1111 docs: regenerate roxygen documentation for paper_bg and force params (#19)
R-CMD-check / R CMD check (pull_request) Successful in 4m29s
2026-08-01 21:44:50 -04:00
kodor f32093c662 fix(test): update theme tests for paper_bg=FALSE default (#19)
R-CMD-check / R CMD check (pull_request) Failing after 5m47s
2026-08-01 21:29:44 -04:00
kodor e257180f15 fix: resolve locked namespace binding in civilytics_load_fonts() and default theme to transparent background
R-CMD-check / R CMD check (pull_request) Failing after 4m13s
- Replace .cv_fonts_loaded <<- TRUE with environment-based state
  (.cv_state) to avoid 'locked namespace binding' error (#18)
- Add force=FALSE argument for idempotent font loading with guard check
- Flip theme_civilytics() paper_bg default to FALSE (transparent) (#7)
- Update roxygen docs and examples for both changes
2026-08-01 02:07:09 -04:00
jared 0ef0f310e2 Merge pull request 'fix(brand): use real company name "Civilytics Consulting" in templates' (#17) from fix/brand-name-consulting into master
R-CMD-check / R CMD check (push) Successful in 4m28s
2026-07-09 16:42:18 -04:00
jared 4fb5c488f8 fix(brand): use real company name "Civilytics Consulting" in templates
R-CMD-check / R CMD check (pull_request) Successful in 4m27s
The title-page kicker in the Typst and LaTeX templates was hardcoded to
"Civilytics Research", which is not a real entity — the company is
Civilytics Consulting. Fix the kicker in both templates, and update the
example report/slides that echoed the same non-real name. Bump to 0.3.1.
2026-07-09 16:41:55 -04:00
15 changed files with 90 additions and 60 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
Package: civilytics
Type: Package
Title: Brand Themes, Color Palettes, and Utility Functions for Civilytics
Version: 0.3.0
Version: 0.3.1
Authors@R:
person("Jared", "E. Knowles", email = "jared@civilytics.com",
role = c("aut", "cre"))
+24 -11
View File
@@ -5,32 +5,45 @@ CV_FONT_SANS <- "Inter" # axis text, legends, UI elements
CV_FONT_SERIF <- "Source Serif 4" # body prose / editorial long-form
CV_FONT_MONO <- "JetBrains Mono" # code, data tables, numeric callouts
# Internal flag so civilytics_load_fonts() is idempotent within a session.
.cv_fonts_loaded <- FALSE
# Mutable package state held in an environment so the binding itself stays
# locked (R locks all namespace bindings at load time) while the contents
# remain writable. See https://adv-r.hadley.nz/environments.html#environments-as-containers
.cv_state <- new.env(parent = emptyenv())
.cv_state$fonts_loaded <- FALSE
#' Load Civilytics brand fonts
#'
#' Downloads Inter and Libre Franklin from Google Fonts via
#' [sysfonts::font_add_google()], then calls [showtext::showtext_auto()] so
#' that all graphics devices render text with those fonts. This is called
#' automatically when the package loads; use this function to retry if the
#' initial load failed (e.g., the machine was offline at load time).
#' Downloads Inter, Libre Franklin, Source Serif 4 and JetBrains Mono from
#' Google Fonts via [sysfonts::font_add_google()], then calls
#' [showtext::showtext_auto()] so that all graphics devices render text with
#' those fonts. This is called automatically when the package loads; use this
#' function to retry if the initial load failed (e.g., the machine was offline
#' at load time).
#'
#' @return Invisibly returns `NULL`.
#' Subsequent calls within the same session are no-ops unless `force = TRUE`.
#'
#' @param force Logical. If `TRUE`, reload fonts even if they were already
#' loaded in this session. Default `FALSE`.
#'
#' @return Invisibly returns `TRUE` if fonts were loaded, `FALSE` if skipped
#' (already loaded and `force = FALSE`).
#' @export
#'
#' @examples
#' \dontrun{
#' civilytics_load_fonts()
#' }
civilytics_load_fonts <- function() {
civilytics_load_fonts <- function(force = FALSE) {
if (.cv_state$fonts_loaded && !force) return(invisible(FALSE))
sysfonts::font_add_google("Inter", family = "Inter")
sysfonts::font_add_google("Libre Franklin", family = "Libre Franklin")
sysfonts::font_add_google("Source Serif 4", family = "Source Serif 4")
sysfonts::font_add_google("JetBrains Mono", family = "JetBrains Mono")
showtext::showtext_auto()
.cv_fonts_loaded <<- TRUE
invisible(NULL)
.cv_state$fonts_loaded <- TRUE
invisible(TRUE)
}
.onLoad <- function(libname, pkgname) {
+10 -8
View File
@@ -36,10 +36,12 @@
#' to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).
#' @param grid Character. Which major gridlines to draw: `"y"` (default,
#' horizontal only), `"x"` (vertical only), `"both"`, or `"none"`.
#' @param paper_bg Logical. If `TRUE` (default), fill the plot and panel
#' backgrounds with the warm `paper` color. Set to `FALSE` for a
#' transparent background (useful for slides or overlay on colored
#' surfaces).
#' @param paper_bg Logical. If `TRUE`, fill the plot and panel backgrounds
#' with the warm `paper` color (Civilytics cream). Default is `FALSE`
#' (transparent) so that figures composite cleanly onto any background.
#' Set to `TRUE` for the branded cream canvas. Note: a transparent device
#' background (e.g., `dev = "ragg_png"`, `dev.args = list(background =
#' "transparent")`) is also needed for fully-transparent PNG exports.
#'
#' @section Font size hierarchy:
#' All text sizes are derived from `font_size` using relative scale factors.
@@ -68,7 +70,7 @@
#' \dontrun{
#' library(ggplot2)
#'
#' # Default editorial theme
#' # Default — transparent background for embedding
#' ggplot(mpg, aes(displ, hwy)) +
#' geom_point() +
#' theme_civilytics()
@@ -79,10 +81,10 @@
#' scale_color_civilytics() +
#' theme_civilytics(grid = "both")
#'
#' # Transparent background for embedding
#' # Branded cream background (opt-in)
#' ggplot(mpg, aes(displ, hwy)) +
#' geom_point() +
#' theme_civilytics(paper_bg = FALSE)
#' theme_civilytics(paper_bg = TRUE)
#'
#' # Larger text for poster or display
#' ggplot(mpg, aes(displ, hwy)) +
@@ -102,7 +104,7 @@ theme_civilytics <- function(
accent = unname(civilytics_colors["ember_600"]),
strip_color = unname(civilytics_colors["paper_2"]),
grid = c("y", "x", "both", "none"),
paper_bg = TRUE) {
paper_bg = FALSE) {
grid <- match.arg(grid)
half_line <- font_size / 2
+1 -1
View File
@@ -2,7 +2,7 @@
title: "Who pays when rent outpaces wages?"
subtitle: "A 12-county analysis of cost-burdened renter households, 2019–2024."
author:
- name: "Civilytics Research"
- name: "Jared Knowles"
affiliation: "Civilytics Consulting"
date: "2026-04-15"
abstract: |
+1 -1
View File
@@ -55,7 +55,7 @@ Big idea goes here.
> Rent has outpaced wages in every county we studied.
Civilytics Research, 2026
Civilytics Consulting, 2026
## Thank you {.thank-you}
+1 -1
View File
@@ -11,7 +11,7 @@
\pagecolor{paper}
\color{ink}
\vspace*{0.5in}
{\sffamily\bfseries\scriptsize\color{ember}\MakeUppercase{— Civilytics Research}\par}
{\sffamily\bfseries\scriptsize\color{ember}\MakeUppercase{— Civilytics Consulting}\par}
\vspace{12pt}
{\displayfont\fontsize{32pt}{34pt}\selectfont\bfseries\color{ink}\thetitle\par}
\vspace{8pt}
+1 -1
View File
@@ -164,7 +164,7 @@
if title != none {
block[
#set text(font: sans-stack, size: 8pt, weight: 600, fill: ember, tracking: 0.1em)
#upper[— Civilytics Research]
#upper[— Civilytics Consulting]
]
v(8pt)
block[
+15 -7
View File
@@ -4,17 +4,25 @@
\alias{civilytics_load_fonts}
\title{Load Civilytics brand fonts}
\usage{
civilytics_load_fonts()
civilytics_load_fonts(force = FALSE)
}
\arguments{
\item{force}{Logical. If \code{TRUE}, reload fonts even if they were already
loaded in this session. Default \code{FALSE}.}
}
\value{
Invisibly returns `NULL`.
Invisibly returns \code{TRUE} if fonts were loaded, \code{FALSE} if skipped
(already loaded and \code{force = FALSE}).
}
\description{
Downloads Inter and Libre Franklin from Google Fonts via
[sysfonts::font_add_google()], then calls [showtext::showtext_auto()] so
that all graphics devices render text with those fonts. This is called
automatically when the package loads; use this function to retry if the
initial load failed (e.g., the machine was offline at load time).
Downloads Inter, Libre Franklin, Source Serif 4 and JetBrains Mono from
Google Fonts via \code{sysfonts::font_add_google()}, then calls
\code{showtext::showtext_auto()} so that all graphics devices render text with
those fonts. This is called automatically when the package loads; use this
function to retry if the initial load failed (e.g., the machine was offline
at load time).
Subsequent calls within the same session are no-ops unless \code{force = TRUE}.
}
\examples{
\dontrun{
+10 -8
View File
@@ -17,7 +17,7 @@ theme_civilytics(
accent = unname(civilytics_colors["ember_600"]),
strip_color = unname(civilytics_colors["paper_2"]),
grid = c("y", "x", "both", "none"),
paper_bg = TRUE
paper_bg = FALSE
)
}
\arguments{
@@ -56,10 +56,12 @@ to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{grid}{Character. Which major gridlines to draw: `"y"` (default,
horizontal only), `"x"` (vertical only), `"both"`, or `"none"`.}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas. Note: a transparent device
background (e.g., `dev = "ragg_png"`, `dev.args = list(background =
"transparent")`) is also needed for fully-transparent PNG exports.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
@@ -105,7 +107,7 @@ shrinkage.
\dontrun{
library(ggplot2)
# Default editorial theme
# Default — transparent background for embedding
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics()
@@ -116,10 +118,10 @@ ggplot(mpg, aes(displ, hwy, colour = class)) +
scale_color_civilytics() +
theme_civilytics(grid = "both")
# Transparent background for embedding
# Branded cream background (opt-in)
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
theme_civilytics(paper_bg = FALSE)
theme_civilytics(paper_bg = TRUE)
# Larger text for poster or display
ggplot(mpg, aes(displ, hwy)) +
+4 -4
View File
@@ -56,10 +56,10 @@ to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{grid}{Character. Which major gridlines to draw: `"y"` (default,
horizontal only), `"x"` (vertical only), `"both"`, or `"none"`.}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
+4 -4
View File
@@ -52,10 +52,10 @@ design system.}
\item{strip_color}{Character. Hex code for facet strip background. Defaults
to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
+4 -4
View File
@@ -52,10 +52,10 @@ design system.}
\item{strip_color}{Character. Hex code for facet strip background. Defaults
to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
+4 -4
View File
@@ -56,10 +56,10 @@ to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{grid}{Character. Which major gridlines to draw: `"y"` (default,
horizontal only), `"x"` (vertical only), `"both"`, or `"none"`.}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
+4 -4
View File
@@ -52,10 +52,10 @@ design system.}
\item{strip_color}{Character. Hex code for facet strip background. Defaults
to [civilytics_colors]`["paper_2"]` (`#F2EDE4`).}
\item{paper_bg}{Logical. If `TRUE` (default), fill the plot and panel
backgrounds with the warm `paper` color. Set to `FALSE` for a
transparent background (useful for slides or overlay on colored
surfaces).}
\item{paper_bg}{Logical. If `TRUE`, fill the plot and panel backgrounds
with the warm `paper` color (Civilytics cream). Default is `FALSE`
(transparent) so that figures composite cleanly onto any background.
Set to `TRUE` for the branded cream canvas.}
}
\value{
A complete ggplot2 [ggplot2::theme()] object.
+6 -1
View File
@@ -133,8 +133,13 @@ test_that("theme_civilytics uses brand ink color for text", {
expect_equal(th$text$colour, unname(civilytics_colors["ink"]))
})
test_that("theme_civilytics uses brand paper color for plot background", {
test_that("theme_civilytics has transparent background by default", {
th <- theme_civilytics()
expect_true(is.na(th$plot.background$fill))
})
test_that("theme_civilytics uses brand paper color when paper_bg = TRUE", {
th <- theme_civilytics(paper_bg = TRUE)
expect_equal(th$plot.background$fill, unname(civilytics_colors["paper"]))
})