新增三个深色颜色(苍松绿 / 暮山紫 / 琥珀橙)并同步要点框自动排布

一、新增颜色(放在 beamercolorthemeOUCSlide.sty)
  oucpine   苍松绿  RGB(30, 86, 64)    白字对比度 8.54
  oucdusk   暮山紫  RGB(92, 58, 118)   白字对比度 9.04
  oucamber  琥珀橙  RGB(196, 82, 16)   白字对比度 4.60
三个都是较深的颜色,与白色文字有足够对比度(WCAG >= 4.5),
可直接作色块底色;各自同样带 10 个色阶(如 oucpine10 ~ oucpine90)。
命名取自中文传统色:「苍松」「暮山紫」「琥珀」。
琥珀橙是高饱和深橘,与低饱和的暗褐「文脉棕」在饱和度上明显区分(0.98 vs 0.61)。

二、要点框自动排布 pointboxgrid(此前仅在 main 上,现同步到本分支)
每行最多 4 个,超过则均匀分成多行(5→3+2;6→3+3;7→4+3;8→4+4;9→3+3+3…),
用法见 README 的「要点框自动排布」一节。

三、验证
本分支已用 TeX Live 2023 重新编译验证:0 错误、0 溢出;
颜色样例页与要点框排布页均正常,三个新颜色在 PDF 中实际生效。
This commit is contained in:
2026-10-13 08:44:15 +08:00
parent 628492b346
commit 24d1517cf2
7 changed files with 325 additions and 12 deletions
+174
View File
@@ -125,6 +125,180 @@
title=#1
}
%% ======================================================================
%% 要点框自动排布:pointboxgrid
%% ----------------------------------------------------------------------
%% 把任意多个要点自动排成「每行最多 4 个」的网格:
%% \begin{pointboxgrid}{高度}
%% \pointitem{标题}{颜色}{内容}
%% ...
%% \end{pointboxgrid}
%%
%% 排布规则(行数尽可能少,并尽量均匀):
%% 1~4 个 → 一行
%% 5 个 → 上行 3 + 下行 2
%% 6 个 → 3 + 3
%% 7 个 → 4 + 3
%% 8 个 → 4 + 4
%% 9 个 → 3 + 3 + 3
%% 10 个 → 4 + 3 + 3
%% 11 个 → 4 + 4 + 3
%% 12 个 → 4 + 4 + 4
%% 一般地:行数 = ceil(N/4),前 N mod 行数 行每行多放 1 个。
%%
%% 说明:
%% - 高度参数与 pointbox 的 height 含义相同(固定高度,内容别超出)。
%% - 较多行时请自行减小高度,避免总高超出页面(建议行数 ≤ 4)。
%% - 「每行最多几个」由 \ouc_pbg_max 控制;间距由 \ouc_pbg_gap /
%% \ouc_pbg_vgap 控制,需要时在导言区改这两个长度。
%% ======================================================================
\ExplSyntaxOn
\int_new:N \l_ouc_pbg_cnt
\int_new:N \l_ouc_pbg_n
\int_new:N \l_ouc_pbg_rows
\int_new:N \l_ouc_pbg_base
\int_new:N \l_ouc_pbg_rem
\int_new:N \l_ouc_pbg_k
\int_new:N \l_ouc_pbg_km
\int_new:N \l_ouc_pbg_i
\int_new:N \l_ouc_pbg_max
\dim_new:N \l_ouc_pbg_est
\dim_new:N \l_ouc_pbg_colw
\dim_new:N \l_ouc_pbg_gap
\dim_new:N \l_ouc_pbg_vgap
\dim_new:N \l_ouc_pbg_h
\int_set:Nn \l_ouc_pbg_max { 4 }
\dim_new:N \l_ouc_pbg_avail
\dim_set:Nn \l_ouc_pbg_avail { 243pt }
\dim_set:Nn \l_ouc_pbg_gap { 8pt }
\dim_set:Nn \l_ouc_pbg_vgap { 6pt }
%% 收集一个要点:内容按原样存进带索引的宏,不做任何展开
\NewDocumentCommand \pointitem { m m m }
{
\int_incr:N \l_ouc_pbg_cnt
\tl_set:cn { l_ouc_pbg_t_ \int_use:N \l_ouc_pbg_cnt } {#1}
\tl_set:cn { l_ouc_pbg_c_ \int_use:N \l_ouc_pbg_cnt } {#2}
\tl_set:cn { l_ouc_pbg_b_ \int_use:N \l_ouc_pbg_cnt } {#3}
}
%% 画一个要点框:按序号直接取用存好的宏
\cs_new_protected:Npn \ouc_pbg_emit:n #1
{
\begin{pointbox}
[ \tl_use:c { l_ouc_pbg_t_#1 } ]
{ \tl_use:c { l_ouc_pbg_c_#1 } }
{ \dim_use:N \l_ouc_pbg_h }
\tl_use:c { l_ouc_pbg_b_#1 }
\end{pointbox}
}
%% 列宽 = (正文宽 - (k-1)*间距) / k
%% 注:某些 TeX Live 下 expl3 的维度乘法(*)会静默算出 0,
%% 因此走 fp_eval + dim_to_fp 的浮点路径,稳妥。
\cs_new_protected:Nn \ouc_pbg_setcolw:
{
\int_set:Nn \l_ouc_pbg_km { \int_use:N \l_ouc_pbg_k - 1 }
\dim_set:Nn \l_ouc_pbg_colw
{
\fp_eval:n
{
( \dim_to_fp:n { \textwidth }
- \int_use:N \l_ouc_pbg_km * \dim_to_fp:n { \l_ouc_pbg_gap } )
/ \int_use:N \l_ouc_pbg_k
}
pt
}
}
\cs_new_protected:Nn \ouc_pbg_typeset:
{
\int_set:Nn \l_ouc_pbg_n { \int_use:N \l_ouc_pbg_cnt }
\int_compare:nNnT { \int_use:N \l_ouc_pbg_n } > { 0 }
{
%% 行数 = ceil(N / max)
\int_set:Nn \l_ouc_pbg_rows
{
\int_div_truncate:nn
{ \int_use:N \l_ouc_pbg_n + \int_use:N \l_ouc_pbg_max - 1 }
{ \int_use:N \l_ouc_pbg_max }
}
%% 均匀分配:前 rem 行每行多 1 个(上行不少于下行)
\int_set:Nn \l_ouc_pbg_base
{
\int_div_truncate:nn
{ \int_use:N \l_ouc_pbg_n } { \int_use:N \l_ouc_pbg_rows }
}
\int_set:Nn \l_ouc_pbg_rem
{
\int_use:N \l_ouc_pbg_n
- \int_use:N \l_ouc_pbg_base * \int_use:N \l_ouc_pbg_rows
}
%% 预估总高度并与正文可用高度比较(公式按实测校准):
%% 总高 ≈ 69pt(首行含标题条) + 行数*高度 + (行数-1)*25pt(行间距)
\dim_set:Nn \l_ouc_pbg_est
{
\fp_eval:n
{
69
+ \int_use:N \l_ouc_pbg_rows * \dim_to_fp:n { \l_ouc_pbg_h }
+ ( \int_use:N \l_ouc_pbg_rows - 1 ) * 25
}
pt
}
\ifdim \l_ouc_pbg_est > \l_ouc_pbg_avail
\PackageWarning{oucslide}
{
要点框共 \int_use:N \l_ouc_pbg_n\space 个,排成
\int_use:N \l_ouc_pbg_rows\space 行、每框高 \dim_use:N \l_ouc_pbg_h,
预估总高 \dim_use:N \l_ouc_pbg_est\space 已超过正文可用高度
\dim_use:N \l_ouc_pbg_avail,可能超出页面底部。
请把高度改小(4 行时建议不超过 24pt)或减少要点个数
}
\fi
\int_zero:N \l_ouc_pbg_i
\int_step_inline:nn { \int_use:N \l_ouc_pbg_rows }
{
\int_set:Nn \l_ouc_pbg_k { \int_use:N \l_ouc_pbg_base }
%% 注意:此处的比较必须用 \ifnum。
%% expl3 的 \int_compare:nNnT 在这套 TeX Live 下判定有误,
%% 会把所有 ##1 都判成"小于等于",导致行内个数分配失效。
\ifnum ##1 > \int_use:N \l_ouc_pbg_rem \else
\int_incr:N \l_ouc_pbg_k
\fi
\ouc_pbg_setcolw:
%% 必须用 [onlytextwidth],否则默认 columns 会带来
%% 左/右边距,4 列时左右各溢出约 10pt。
\begin{columns}[onlytextwidth]
\int_step_inline:nn { \int_use:N \l_ouc_pbg_k }
{
\int_incr:N \l_ouc_pbg_i
\begin{column}{\dim_use:N \l_ouc_pbg_colw}
\ouc_pbg_emit:n { \int_use:N \l_ouc_pbg_i }
\end{column}
}
\end{columns}
\ifnum ##1 < \int_use:N \l_ouc_pbg_rows
\vspace{\dim_use:N \l_ouc_pbg_vgap}
\fi
}
}
}
%% 友好设置:\pointboxsetup{每行最多几个}{横向间距}{纵向间距}
%% 例如 \pointboxsetup{5}{6pt}{4pt}
\NewDocumentCommand \pointboxsetup { m m m }
{
\int_set:Nn \l_ouc_pbg_max {#1}
\dim_set:Nn \l_ouc_pbg_gap {#2}
\dim_set:Nn \l_ouc_pbg_vgap {#3}
}
\NewDocumentEnvironment { pointboxgrid } { m }
{ \int_zero:N \l_ouc_pbg_cnt \dim_set:Nn \l_ouc_pbg_h {#1} }
{ \ouc_pbg_typeset: }
\ExplSyntaxOff
%文本框textbox
\newtcolorbox{textbox}[1]{
colback=#1!5!white,