use crate::list::{self, cell_part_class};
use crate::{Emit, class, gated};
use makeover_geometry::{Density, Gap};
use makeover_layout::CellPart;
use std::fmt::Write as _;
const CH_REM: f32 = 0.5625;
const TABLE_TYPE: &str = "var(--text-note)";
pub(crate) fn table_rules(opts: &Emit) -> String {
let table = class("table", opts);
let head = class("table-head", opts);
let row = class("table-row", opts);
let heading = class("table-heading", opts);
let cell = class("cell", opts);
let mut css = String::new();
let bw = opts.border_width;
let cell_in = class("cell-in", opts);
let _ = writeln!(
css,
".{table} {{\n border: {bw} solid var(--row-rule);\n \
background: var(--surface-raised);\n font-size: {TABLE_TYPE};\n}}"
);
let _ = writeln!(
css,
".{table} .{head},\n.{table} .{row} {{\n display: flex;\n}}"
);
let _ = writeln!(
css,
".{table} .{row} {{\n min-height: var(--row-block);\n}}"
);
let _ = writeln!(
css,
".{table} .{heading},\n.{table} .{cell} {{\n display: flex;\n \
align-items: center;\n flex: 0 1 calc({}rem + 2 * var(--gap-group));\n \
min-width: 0;\n overflow: hidden;\n container-type: inline-size;\n}}",
8.0 * CH_REM
);
let _ = writeln!(
css,
".{table} .{cell_in} {{\n flex: 1 1 auto;\n min-width: 0;\n \
overflow: hidden;\n text-overflow: ellipsis;\n}}"
);
let _ = writeln!(
css,
".{table} .{head} {{\n color: var(--content-secondary);\n \
background: var(--surface-sunken);\n}}"
);
let _ = writeln!(
css,
".{table} .{heading} {{\n align-items: flex-end;\n \
background: var(--surface-sunken);\n border-bottom: {bw} solid var(--bevel-dark);\n}}"
);
let _ = writeln!(
css,
".{table} .{heading} > .{cell_in} {{\n padding: var(--gap-peer) var(--gap-group);\n \
font-size: var(--text-fine);\n font-weight: bold;\n \
letter-spacing: var(--table-heading-tracking, 0.06em);\n \
text-transform: uppercase;\n text-align: start;\n white-space: nowrap;\n}}"
);
let _ = writeln!(
css,
".{table} .{row} > .{cell} > .{cell_in} {{\n padding: var(--gap-bound) var(--gap-group);\n}}"
);
let _ = writeln!(
css,
".{table} .{row} + .{row} {{\n border-top: {bw} solid var(--row-rule);\n}}"
);
let _ = writeln!(
css,
".{table} .{row}:nth-child(even of .{row}) {{\n background: var(--row-stripe);\n}}"
);
let _ = writeln!(
css,
"@media (hover: hover) and (pointer: fine) {{\n \
.{table} .{row}:hover {{\n background: var(--row-hover);\n }}\n}}"
);
let [
kind_identifier,
kind_date,
kind_number,
kind_status,
kind_actions,
kind_code,
] = [
"kind-identifier",
"kind-date",
"kind-number",
"kind-status",
"kind-actions",
"kind-code",
]
.map(|name| class(name, opts));
let _ = writeln!(
css,
".{table} .{cell}.{kind_identifier} > .{cell_in} {{\n font-family: var(--font-mono);\n \
font-size: var(--text-fine);\n overflow-wrap: anywhere;\n}}"
);
let _ = writeln!(
css,
".{table} .{kind_date} > .{cell_in} {{\n white-space: nowrap;\n}}\n\
.{table} .{cell}.{kind_date} > .{cell_in} {{\n font-variant-numeric: tabular-nums;\n}}"
);
let _ = writeln!(
css,
".{table} .{kind_number} > .{cell_in} {{\n white-space: nowrap;\n text-align: end;\n}}\n\
.{table} .{cell}.{kind_number} > .{cell_in} {{\n font-variant-numeric: tabular-nums;\n}}"
);
let _ = writeln!(
css,
".{table} .{kind_status} > .{cell_in} {{\n white-space: nowrap;\n}}"
);
let _ = writeln!(
css,
".{table} .{kind_actions} > .{cell_in} {{\n white-space: nowrap;\n text-align: end;\n}}"
);
let _ = writeln!(
css,
".{table} .{cell}.{kind_code} > .{cell_in} {{\n font-family: var(--font-mono);\n \
white-space: pre;\n}}"
);
let code = format!(".{table}:has(.{kind_code})");
let _ = writeln!(
css,
"{code} {{\n overflow-x: auto;\n}}\n\
{code} .{head},\n{code} .{row} {{\n min-width: max-content;\n}}\n\
{code} .{row} {{\n min-height: auto;\n align-items: baseline;\n}}\n\
{code} .{row} + .{row} {{\n border-top: 0;\n}}\n\
{code} .{row} > .{cell} > .{cell_in} {{\n padding-block: 0;\n}}\n\
{code} .{cell}.{kind_code},\n{code} .{heading}.{kind_code} {{\n \
flex: 1 0 auto;\n overflow: visible;\n container-type: normal;\n}}\n\
{code} .{row}:nth-child(even of .{row}) {{\n background: none;\n}}"
);
let _ = writeln!(
css,
"@media (hover: hover) and (pointer: fine) {{\n \
{code} .{row}:hover {{\n background: none;\n }}\n}}"
);
let _ = writeln!(
css,
".{table} .{} {{\n flex-grow: 1;\n}}",
class("cell-fill", opts)
);
let _ = writeln!(
css,
".{table} .{} > .{cell_in} {{\n overflow-wrap: anywhere;\n}}",
class("cell-fill", opts)
);
let _ = writeln!(
css,
".{table} .{} > .{cell_in},\n.{table} .{} > .{cell_in} {{\n white-space: nowrap;\n}}",
class("cell-content", opts),
class("cell-fixed", opts)
);
let [drops_first, drops_next, keeps] =
["cell-drops-first", "cell-drops-next", "cell-keeps"].map(|name| class(name, opts));
let _ = writeln!(
css,
".{table} .{drops_first} {{\n flex-shrink: 1000000;\n}}\n\
.{table} .{drops_next} {{\n flex-shrink: 1000;\n}}"
);
let holding: Vec<String> = [
makeover_layout::ColumnKind::Text,
makeover_layout::ColumnKind::Identifier,
makeover_layout::ColumnKind::Date,
makeover_layout::ColumnKind::Number,
makeover_layout::ColumnKind::Code,
makeover_layout::ColumnKind::Status,
makeover_layout::ColumnKind::Actions,
]
.into_iter()
.filter(|kind| kind.holds_minimum())
.filter_map(list::kind_class)
.map(|name| format!(".{}", class(name, opts)))
.collect();
let _ = writeln!(
css,
".{table} .{keeps}:is({}) {{\n flex-shrink: 0;\n}}",
holding.join(", ")
);
let sizer = class(list::CELL_SIZER, opts);
let _ = writeln!(
css,
".{table} .{keeps}:has(> .{cell_in} > .{sizer}) {{\n flex-basis: auto;\n \
container-type: normal;\n}}\n\
.{table} .{sizer} {{\n display: block;\n block-size: 0;\n overflow: hidden;\n \
visibility: hidden;\n white-space: nowrap;\n font-size: {TABLE_TYPE};\n \
font-weight: normal;\n letter-spacing: normal;\n text-transform: none;\n}}\n\
.{table} .{sizer} > * {{\n display: flex;\n inline-size: max-content;\n}}"
);
let rungs = (2..=makeover_layout::MIN_CEILING).step_by(2);
for n in rungs.clone() {
let _ = writeln!(
css,
".{table} .{} {{\n flex-basis: calc({}rem + 2 * var(--gap-group));\n}}",
class(&format!("min-{n}"), opts),
f32::from(n) * CH_REM
);
}
for density in [Density::Pointer, Density::Touch] {
let step = Gap::Group.step_at(density).ratio();
let edge = f32::from(step.numerator) / f32::from(step.denominator);
let mut block = String::new();
for n in rungs.clone() {
let _ = writeln!(
block,
"@container (inline-size < {}rem) {{\n \
.{table} :is(.{drops_first}, .{drops_next}).{} > .{cell_in} {{\n \
visibility: hidden;\n max-block-size: 0;\n overflow: hidden;\n }}\n}}",
f32::from(n) * CH_REM + edge,
class(&format!("min-{n}"), opts)
);
let _ = writeln!(
block,
"@container (inline-size < {}rem) {{\n \
.{table} .{keeps}.{fill}.{} > .{cell_in} {{\n \
white-space: nowrap;\n overflow-wrap: normal;\n }}\n}}",
f32::from(n) * CH_REM + edge,
class(&format!("min-{n}"), opts),
fill = class("cell-fill", opts),
);
}
match density {
Density::Pointer => css.push_str(&block),
Density::Touch => css.push_str(&gated(Some(density.media_condition()), &block)),
}
}
for part in [
CellPart::Value,
CellPart::Tokens,
CellPart::Actions,
CellPart::Link,
] {
if !matches!(part, CellPart::Tokens | CellPart::Actions) {
let underline = if part == CellPart::Link {
"\n text-decoration: none;"
} else {
""
};
let _ = writeln!(
css,
".{} {{\n color: var(--{});{underline}\n}}",
class(cell_part_class(part), opts),
part.intent()
);
}
}
css
}