diff --git a/themes/revision/colors.typ b/themes/revision/colors.typ new file mode 100644 index 0000000..4ea284a --- /dev/null +++ b/themes/revision/colors.typ @@ -0,0 +1,17 @@ +#let red = rgb("#F43545").lighten(50%) +#let orange = rgb("#FA8901").lighten(50%) +#let yellow = rgb("#FAD717").lighten(50%) +#let green = rgb("#00BA71").lighten(50%) +#let blue = rgb("#00C2DE").lighten(50%) +#let indigo = rgb("#00418D").lighten(50%) +#let violet = rgb("#5F2879").lighten(50%) + +#let color-map = ( + "identify" : red, + "brainstorm" : orange, + "select" : yellow, + "build" : green, + "program" : blue, + "test" : indigo, + "improve" : violet, +) \ No newline at end of file diff --git a/themes/revision/components/components.typ b/themes/revision/components/components.typ new file mode 100644 index 0000000..a29fa14 --- /dev/null +++ b/themes/revision/components/components.typ @@ -0,0 +1,8 @@ +#import "./decision-matrix.typ": * +#import "./gantt-chart.typ": * +#import "./glossary.typ": * +#import "./header.typ": * +#import "./pro-con.typ": * +#import "./result-table.typ": * +#import "./toc.typ": * +#import "./tournament.typ": * \ No newline at end of file diff --git a/themes/revision/components/decision-matrix.typ b/themes/revision/components/decision-matrix.typ new file mode 100644 index 0000000..e53be83 --- /dev/null +++ b/themes/revision/components/decision-matrix.typ @@ -0,0 +1,34 @@ +#import "/utils.typ" +#import "/packages.typ": tablex +#import "../colors.typ": * +#import tablex: * + +#let decision-matrix(properties: none, ..choices) = { + let data = utils.calc-decision-matrix(properties: properties, ..choices) + rect(inset: 0.5pt)[ + #table( + stroke: (), + inset: 0.75em, + columns: properties.len() + 2, + rows: auto, + [], + ..for property in properties { + (align(center)[#property.name],) + }, + align(center)[Total], + ..for choice in data { + if choice.values.total.highest {( + table.cell(fill: green)[#align(center)[#choice.name]], + ..for value in choice.values {( + table.cell(fill: green)[#align(center)[#value.at(1).value]], + )} + ,)} else {( + align(center)[#choice.name], + ..for value in choice.values {( + align(center)[#value.at(1).value], + )} + ,)} + }, + ) + ] +} \ No newline at end of file diff --git a/themes/revision/components/gantt-chart.typ b/themes/revision/components/gantt-chart.typ new file mode 100644 index 0000000..4bd8110 --- /dev/null +++ b/themes/revision/components/gantt-chart.typ @@ -0,0 +1,93 @@ +#import "/packages.typ": timeliney +#import "../colors.typ": * + +#let gantt-chart( + start: datetime, + end: datetime, + date-interval: 1, + date-format: "[month]/[day]", + tasks: (), + goals: none, +) = { + timeliney.timeline( + spacing: 5pt, + + show-grid: true, + grid-style: (stroke: (dash: none, thickness: .2pt, paint: black)), + + tasks-vline: true, + line-style: (stroke: 0pt), + + milestone-overhang: 3pt, + milestone-layout: "in-place", + box-milestones: true, + milestone-line-style: (stroke: (dash: none, thickness: 1pt, paint: black)), + { + import timeliney: * + + let difference = end - start + let dates-array = () + let months-array = () + let month-len = 0 + let last-month = start.month() + let next + + for value in range(int((difference.days())/date-interval)+1) { + next = start + duration(days: (value*date-interval)) + dates-array.push(group(((next).display(date-format),1))) + if next.month() == last-month { + month-len += 1 + last-month = next.month() + } else { + months-array.push(group(((datetime(year: next.year(), month: last-month, day: 1)).display("[month repr:long]"),month-len))) + month-len = 1 + last-month = next.month() + } + } + months-array.push(group(((datetime(year: next.year(), month: last-month, day: 1)).display("[month repr:long]"),month-len))) + + headerline(..months-array) + headerline(..dates-array) + + let goal-color + + if goals != none { + for goal in goals { + if goal.len() == 2 { + goal-color = none + } else { + goal-color = goal.at(2) + } + milestone( + at: goal.at(1), + style: (stroke: 0pt), + [ + #place(center, dy: -8pt)[#line(angle: 90deg, length: 6pt)] + #box(fill: goal-color, outset: 3pt, radius: 1.5pt)[#goal.at(0)] + ], + ) + } + } + + let colors = (red, orange, yellow, green, blue, violet) + let index = 0 + let size = difference.days()/date-interval + let pos = () + + taskgroup({ + for item in tasks { + pos = (item.at(1).at(0)+0.054, item.at(1).at(1)-0.054) + if item.len() == 2 { + if index == colors.len()-1 { + index = 0 + } + task(item.at(0), pos, style: (stroke: (paint: colors.at(index), thickness: 5pt, cap: "square"))) + index += 1 + } else { + task(item.at(0), pos, style: (stroke: (paint: item.at(2), thickness: 5pt, cap: "square"))) + } + } + }) + } + ) +} diff --git a/themes/revision/components/glossary.typ b/themes/revision/components/glossary.typ new file mode 100644 index 0000000..b398546 --- /dev/null +++ b/themes/revision/components/glossary.typ @@ -0,0 +1,25 @@ +#import "/utils.typ" + +#let glossary() = utils.print-glossary(glossary => { + stack( + spacing: 2em, + dir: ttb, + [#grid( + rows: 1em, + columns: (25%, 75%), + + align(left)[TERM], + align(left)[DEFENITION], + )], + ..for entry in glossary { + ([ + #grid( + columns: (25%, 75%), + rows: auto, + [=== #entry.word], + [#entry.definition] + ) + ],) + } + ) +}) diff --git a/themes/revision/components/header.typ b/themes/revision/components/header.typ new file mode 100644 index 0000000..05c912b --- /dev/null +++ b/themes/revision/components/header.typ @@ -0,0 +1,13 @@ +#let header-map = ( + "identify" : "Identify Problem", + "brainstorm" : "Brainstorm Solutions", + "select" : "Select and Plan", + "build" : "Build Solution", + "test" : "Test Solution", + "program" : "Program Solution", + "improve" : "Improve Solution" +) + +#let header(title) = { + rect(height: auto, width: auto)[=== #title] +} \ No newline at end of file diff --git a/themes/revision/components/pro-con.typ b/themes/revision/components/pro-con.typ new file mode 100644 index 0000000..1ffe69c --- /dev/null +++ b/themes/revision/components/pro-con.typ @@ -0,0 +1,21 @@ +#import "../colors.typ": * + +#let pro-con(pros: [], cons: []) = { + table( + columns: (50%, 50%), + inset: 0.75em, + fill: (col, row) => + if row == 0 { + if col == 0 { + green + } + if col == 1 { + red + } + }, + align(left)[Positives], + align(left)[Negatives], + pros, + cons + ) +} \ No newline at end of file diff --git a/themes/revision/components/result-table.typ b/themes/revision/components/result-table.typ new file mode 100644 index 0000000..137b72a --- /dev/null +++ b/themes/revision/components/result-table.typ @@ -0,0 +1,7 @@ +#let result-table( + trial-count: 1, + subject: (), + data: () +) = { + table() +} \ No newline at end of file diff --git a/themes/revision/components/toc.typ b/themes/revision/components/toc.typ new file mode 100644 index 0000000..1d3c547 --- /dev/null +++ b/themes/revision/components/toc.typ @@ -0,0 +1,77 @@ +#import "/utils.typ" +#import "/themes/revision/colors.typ": * +#import "header.typ": header-map + +#let toc() = utils.print-toc((frontmatter, body, appendix) => { + let last-page = 0 + let previous-color + + stack( + spacing: none, + [#heading(level: 1)[ENTRIES]#v(1em)], + [#grid( + rows: 1em, + columns: (1fr, 10fr, 2fr), + align(center)[PAGE], + align(center)[SUBJECT], + align(center)[DATE] + )], + ..for entry in body { + if entry.at("page-number") - last-page > 1 { + for i in range(entry.at("page-number") - last-page - 2) { + ([#table( + stroke: (luma(120) + 0.5pt), + rows: (18pt), + columns: (1fr, 10fr, 2fr), + align(center)[#(last-page + i + 1)], + align(horizon)[#place(dx: 35pt)[#rect(height: 18.5pt, width: 1pt, fill: black, stroke: 0pt)]], + [] + )],) + } + let i = entry.at("page-number") - last-page -1 + ([#table( + stroke: (luma(120) + 0.5pt), + rows: (18pt), + columns: (1fr, 10fr, 2fr), + align(center)[#(last-page + i + 1)], + align(horizon)[#place(dx: 35pt, dy: -4.25pt)[#rect(height: 10pt, width: 1pt, fill: black, stroke: 0pt)#place(center)[#rotate(180deg)[#polygon.regular(size: 5pt, fill: black)]]]], + [] + )],) + } + ([#table( + stroke: (luma(120) + 0.5pt), + rows: (18pt), + columns: (1fr, 10fr, 2fr), + align(center)[#entry.at("page-number")], + if entry.at("type") != none { + previous-color = color-map.at(entry.at("type")) + align(left)[#highlight(fill: previous-color, radius: 2pt, extent: 2pt)[ + #header-map.at(entry.at("type"))] #h(2pt)$->$ #entry.at("title")] + } else { + align(left)[#entry.at("title")] + }, + align(center)[#entry.at("date").display("[month]/[day]/[year]")] + )],) + + last-page = entry.at("page-number") + }, + [#v(2em) #heading(level: 1)[APPENDIX] #v(1em)], + [#grid( + rows: 1em, + columns: (1fr, 10fr, 2fr), + align(center)[PAGE], + align(center)[SUBJECT], + align(center)[DATE] + )], + ..for entry in appendix { + ([#table( + stroke: (luma(120) + 0.5pt), + rows: (18pt), + columns: (1fr, 10fr, 2fr), + align(center)[#numbering("I", entry.at("page-number"))], + align(left)[#entry.at("title")], + align(center)[#entry.at("date").display("[month]/[day]/[year]")] + )],) + } + ) +}) \ No newline at end of file diff --git a/themes/revision/components/tournament.typ b/themes/revision/components/tournament.typ new file mode 100644 index 0000000..e69de29 diff --git a/themes/revision/entries.typ b/themes/revision/entries.typ new file mode 100644 index 0000000..2ee9c66 --- /dev/null +++ b/themes/revision/entries.typ @@ -0,0 +1,123 @@ +#import "colors.typ": * +#import "components/header.typ": header-map + +#let frontmatter-entry(ctx: (:), body) = { + show: page.with( + paper: "us-letter", + margin: (y: 90pt), + header: align(center)[ + #text(size:24pt)[#upper(ctx.title)] \ + #line(length: 100%) + ], + footer: grid( + rows: (10pt, auto), + columns: (auto, auto, auto), + column-gutter: 10pt, + row-gutter: 10pt, + align(horizon+right)[#line(length: 100%)], + align(top)[#context(counter(page).display("I"))], + align(horizon+left)[#line(length: 100%)], + if (ctx.type != "toc") { + align(left)[#text(weight: "bold")[Authors:]] + } else {[]}, + [], + if (ctx.date != none) { + align(right)[#text(weight: "bold")[Date:] #ctx.date.display("[month]/[day]/[year]")] + } else {[]} + ) + ) + body +} + +#let body-entry(ctx: (:), body) = { + show: page.with( + paper: "us-letter", + margin: (y: 90pt), + header: + if ctx.type != none { + align(center)[ + #text(size:24pt)[#upper(header-map.at(ctx.type))] \ + #grid( + rows: 10pt, + columns: (auto, auto, auto), + column-gutter: 10pt, + align(horizon+right)[#line(length: 100%)], + align(top)[#ctx.title], + align(horizon+left)[#line(length: 100%)] + ) + ] + } else { + align(center)[ + #text(size:24pt)[#upper(ctx.title)] \ + #line(length: 100%) + ] + }, + footer: grid( + rows: (10pt, auto), + columns: (auto, auto, auto), + column-gutter: 10pt, + row-gutter: 10pt, + align(horizon+right)[#line(length: 100%)], + align(top)[#context(counter(page).display())], + align(horizon+left)[#line(length: 100%)], + align(left)[#text(weight: "bold")[Authors:]], + [], + align(right)[#text(weight: "bold")[Date:] #ctx.date.display("[month]/[day]/[year]")] + ) + ) + context(if calc.even(here().position().at("page")) and ctx.type != none { + place(left + top, dx: -35pt, dy: -33.5pt)[ + #box(fill: color-map.at(ctx.type), height: 100% + 66pt, width: 5%)[ + #align(horizon)[ + #rotate(90deg, origin : center, reflow: true)[ + #upper(header-map.at(ctx.type))#v(40%) + ] + ] + ] + ] + } else if ctx.type != none { + place(right + top, dx: 35pt, dy: -33.5pt)[ + #box(fill: color-map.at(ctx.type), height: 100% + 66pt, width: 5%)[ + #align(horizon)[ + #rotate(90deg, origin : center, reflow: true)[ + #v(40%)#upper(header-map.at(ctx.type)) + ] + ] + ] + ] + }) + body +} + +#let appendix-entry(ctx: (:), body) = { + show: page.with( + paper: "us-letter", + margin: (y: 90pt), + header: align(center)[ + #text(size:24pt)[#upper(ctx.title)] \ + #line(length: 100%) + ], + footer: grid( + rows: (10pt, auto), + columns: (auto, auto, auto), + column-gutter: 10pt, + row-gutter: 10pt, + align(horizon+right)[#line(length: 100%)], + align(top)[#context(counter(page).display("I"))], + align(horizon+left)[#line(length: 100%)], + align(left)[#text(weight: "bold")[Authors:]], + [], + if (ctx.date != none) { + align(right)[#text(weight: "bold")[Date:] #ctx.date.display("[month]/[day]/[year]")] + } else {[]} + ) + ) + body +} + +#let cover(ctx: (:)) = [ + #set align(center) + #text(size: 26pt)[ \ \ \ \ + == ENGINEERING NOTEBOOK + ] +] \ No newline at end of file diff --git a/themes/revision/revision.typ b/themes/revision/revision.typ new file mode 100644 index 0000000..ff6d032 --- /dev/null +++ b/themes/revision/revision.typ @@ -0,0 +1,12 @@ +#import "./entries.typ": * +#import "./rules.typ": * +#import "colors.typ": * +#import "./components/components.typ" + +#let revision-theme = ( + rules: rules, + cover: cover, + frontmatter-entry: frontmatter-entry, + body-entry: body-entry, + appendix-entry: appendix-entry, +) \ No newline at end of file diff --git a/themes/revision/rules.typ b/themes/revision/rules.typ new file mode 100644 index 0000000..95d6a39 --- /dev/null +++ b/themes/revision/rules.typ @@ -0,0 +1,14 @@ +#let rules(doc) = { + set text(font: "linux libertine", size: 12pt) + set page("us-letter") + + // Enforce the correct font on Excalidraw drawings + show image: it => [ + #align(center)[ + #set text(font: "Virgil 3 YOFF") + #it + ] + ] + + doc +} \ No newline at end of file