%% *********************************************************** %% Copyright 2024 by Mingyu XIA * %% * %% This work may be distributed and/or modified under * %% the conditions of the LaTeX Project Public License * %% * %% http://www.latex-project.org/lppl.txt * %% * %% either version 1.3c of this license or any later * %% version. * %% * %% This work has the LPPL maintenance status `maintained'. * %% * %% The Current Maintainer of this work is Mingyu XIA. * %% * %% This work consists of the files litetable.cls, * %% and README.md. * %% available at https://github.com/xiamyphys/litetable * %% *********************************************************** \ProvidesExplClass{litetable}{2024/09/25}{3.0B}{Course Schedule} \ExplSyntaxOff \DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} \ProcessOptions\relax \LoadClass{article} \pagestyle{empty} \RequirePackage{listofitems,tikz,xcolor} \ignoreemptyitems\setsepchar{,/->} \usetikzlibrary{calc} \definecolor{darkergray}{HTML}{F4F6F8}% Blocks \ExplSyntaxOn \int_new:N \l_time_num_int \dim_new:N \l__time_vunit_dim \msg_new:nnn {litetable} {timelist} {\noexpand\timelist~extra~time~group(s)~were~ignored} \NewDocumentCommand{\timelist}{om} { \IfBlankTF{#2} { \int_set:Nn \l_time_num_int { #1 } \tl_clear:N \@timelist }{ \readlist*\@timelist{#2} \IfNoValueTF{#1} { \int_set:Nn \l_time_num_int {\@timelistlen} }{ \int_set:Nn \l_time_num_int { #1 } \int_compare:nNnT {\@timelistlen} > {#1} { \msg_warning:nn {litetable} {timelist} } } } \dim_set:Nn \l__time_vunit_dim { \fp_eval:n {1/(2*\l_time_num_int+3.5)}\paperheight } } \clist_new:N \l__week_ratios_clist \clist_new:N \l__week_accum_clist \int_new:N \l__week_num_int \dim_new:N \l__week_hunit_dim \NewDocumentCommand{\weeklist}{om} { \IfValueT{ #1 }{\tl_set:Nn \l_weeks_tl { #1 }} \readlist*\@weeklist{#2} \int_step_inline:nn {\@weeklistlen} { \clist_put_right:Ne \l__week_ratios_clist { \@weeklist[##1,2] } } \int_step_inline:nn {\@weeklistlen} { \clist_clear:N \l__week_accumtmp_clist \int_step_inline:nn { ##1 } { \clist_put_right:Ne \l__week_accumtmp_clist { \clist_item:Nn \l__week_ratios_clist { ####1 } } } \clist_put_right:Ne \l__week_accum_clist { \int_eval:n { \clist_use:Nn \l__week_accumtmp_clist { + } } } } \int_set:Nn \l__week_num_int { \clist_item:Nn \l__week_accum_clist { \@weeklistlen } } \dim_set:Nn \l__week_hunit_dim { \fp_eval:n {1/\l__week_num_int*14/15}\paperwidth } } \int_new:N \l__week_day_int \newcommand{\newday}{\int_incr:N \l__week_day_int} \NewDocumentCommand{\maketable}{om}{ % Gray Block at top \fill [ darkergray ] (current~page.north~west) rectangle + (\paperwidth,{-1.5*\l__time_vunit_dim}) node [ midway, black, font = \huge\bfseries ] {#2}; \IfValueT{#1}% Semester { \node [ left, rectangle, fill = DarkBlue!10, text = DarkBlue!60, inner~sep = 2ex, rounded~corners = 8pt, font = \large ] at ($ (current~page.north~east)+ (-.02\paperwidth,-.75*\l__time_vunit_dim) $) {\ensuremath\rightleftharpoons\ #1}; } % Darker Blocks \int_step_inline:nnnn {0} {2} {\l_time_num_int} { \filldraw [ fill = darkergray, draw = gray, thick, densely~dashed, line~cap = round ] ([yshift = -2*##1*\l__time_vunit_dim]$ (current~page.north~west)+(-.4pt,0)+ (0,-2.5*\l__time_vunit_dim) $) rectangle + ($ (\paperwidth,-2*\l__time_vunit_dim)+ (.8pt,0) $); } \tl_if_empty:NTF {\@timelist}% Classes numbering { \int_step_inline:nn {\l_time_num_int} { \node [ yshift = -2*##1*\l__time_vunit_dim, darkgray!80, font = \bfseries\large\ttfamily ] at ($ (current~page.north~west)+ (\paperwidth/30,-1.5*\l__time_vunit_dim) $) {##1}; } }{ \int_step_inline:nn {\l_time_num_int} { \node [ yshift = -2*##1*\l__time_vunit_dim, darkgray!80, font = \bfseries\large\ttfamily ] at ($ (current~page.north~west)+ (\paperwidth/30,-\l__time_vunit_dim) $) {##1}; } % Classes time \int_step_inline:nn {\@timelistlen} { \node [ yshift = -2*##1*\l__time_vunit_dim, gray, font = \ttfamily ,align = center] at ($ (current~page.north~west)+ (\paperwidth/30,-1.9*\l__time_vunit_dim) $) {\@timelist[##1,1]\\\@timelist[##1,2]}; } } % Weekdays \int_step_inline:nn {\@weeklistlen} { \node [ font = \large\bfseries, xshift = \clist_item:Nn \l__week_accum_clist {##1}/ \l__week_num_int*14/15*\paperwidth ] at ($ (current~page.north~west)- (\fp_eval:n {( \clist_item:Nn \l__week_ratios_clist { ##1 } /2)/\l__week_num_int*14/15-1/15 }*\paperwidth,2*\l__time_vunit_dim) $) {\@weeklist[##1,1]}; } } \keys_define:nn{course}{ color.tl_set:N = \l_color_tl, color.initial:n = teal, subject.tl_set:N = \l_subject_tl, teacher.tl_set:N = \l_teacher_tl, location.tl_set:N = \l_location_tl, weeks.tl_set:N = \l_weeks_tl, weeks.initial:n = \l_weeks_tl, } \dim_new:N \l__course_infoshift_dim \NewDocumentCommand{\course}{O{}mm} { \group_begin: \keys_set:nn { course } { #1 } % Course block fg \fill [ \l_color_tl!60, rounded~corners = 8pt ] ($ (current~page.north~west)+(.4pt,-.4pt)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int } }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-.5-2*#2}*\l__time_vunit_dim) $) rectangle ($ (current~page.north~west)+(-.4pt,.4pt)+ (\clist_item:Nn \l__week_accum_clist { \l__week_day_int }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-2.5-2*#3}*\l__time_vunit_dim) $); % Course block bg \fill [ \l_color_tl!10 ] ($ (current~page.north~west)+(1.2pt,-.4pt)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int } }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1-2*#2}*\l__time_vunit_dim) $) -- ($ (current~page.north~west)+(-1.2pt,-.4pt)+ (\clist_item:Nn \l__week_accum_clist { \l__week_day_int }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1-2*#2}*\l__time_vunit_dim) $) {[rounded~corners = 7.2pt] -- ($ (current~page.north~west)+(-1.2pt,1.2pt)+ (\clist_item:Nn \l__week_accum_clist { \l__week_day_int }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-2.5-2*#3}*\l__time_vunit_dim) $) -- ($ (current~page.north~west)+(1.2pt,1.2pt)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int } }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-2.5-2*#3}*\l__time_vunit_dim) $)} -- cycle; % Course info \tl_if_eq:NNTF {#2} {#3}% Single-unit height course block { \bool_if:nTF { \tl_if_empty_p:N \l_location_tl && \tl_if_empty_p:N \l_teacher_tl }{ \tl_set:Nn \l_shortcourse_anchor_tl { } }{ \tl_set:Nn \l_shortcourse_anchor_tl { above } } \cs_if_exist:NT {\l_subject_tl } { \node [ \l_shortcourse_anchor_tl, \l_color_tl!60, align = center, font = \large\bfseries ] at ($ (current~page.north~west)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int }/2 }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1.75-#2-#3}*\l__time_vunit_dim) $) { \l_subject_tl }; } \bool_if:nTF { !\tl_if_empty_p:N \l_location_tl && !\tl_if_empty_p:N \l_teacher_tl }{ \tl_set:Nn \l_shortcourse_sep_tl { ,~ } }{ \tl_set:Nn \l_shortcourse_sep_tl { } } \node [ below, \l_color_tl!60, align = center ] at ($ (current~page.north~west)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int }/2 }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1.75-#2-#3}*\l__time_vunit_dim) $) { \tl_if_exist:NT { \l_location_tl } { \l_location_tl } \l_shortcourse_sep_tl \tl_if_exist:NT { \l_teacher_tl } { \l_teacher_tl } }; }{ \bool_if:nTF% Multiply-unit height course block { \tl_if_empty_p:N \l_location_tl && \tl_if_empty_p:N \l_teacher_tl }{ \tl_set:Nn \l_course_anchor_tl {} \dim_set:Nn \l__course_infoshift_dim { 0pt } }{ \tl_set:Nn \l_course_anchor_tl { above } \dim_set:Nn \l__course_infoshift_dim { .125\l__time_vunit_dim } } \cs_if_exist:NT { \l_subject_tl } { \node [ \l_course_anchor_tl, yshift = \l__course_infoshift_dim, \l_color_tl!60, align = center, font = \large\bfseries ] at ($ (current~page.north~west)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int }/2 }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1.5-#2-#3}*\l__time_vunit_dim) $) { \l_subject_tl }; } \bool_if:nTF { !\tl_if_empty_p:N \l_location_tl && !\tl_if_empty_p:N \l_teacher_tl }{ \tl_set:Nn \l_courseinfo_sep_tl { \\ } }{ \tl_set:Nn \l_courseinfo_sep_tl { } } \node [ below, \l_color_tl!60, align = center ] at ($ (current~page.north~west)+ (\fp_eval:n { \clist_item:Nn \l__week_accum_clist { \l__week_day_int }- \clist_item:Nn \l__week_ratios_clist { \l__week_day_int }/2 }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-1.625-#2-#3}*\l__time_vunit_dim) $) { \tl_if_exist:NT { \l_location_tl } { \l_location_tl } \l_courseinfo_sep_tl \tl_if_exist:NT { \l_teacher_tl } { \l_teacher_tl } }; \node [ above~left, \l_color_tl!60, outer~sep = .5ex ] at ($ (current~page.north~west)+ (\clist_item:Nn \l__week_accum_clist { \l__week_day_int }*\l__week_hunit_dim+\paperwidth/15, \fp_eval:n {-2.5-2*#3}*\l__time_vunit_dim) $) { \l_weeks_tl }; } \group_end: } \newcommand{\more}[1]% Additional info { \node [ left = 1ex, darkgray, font = \small\bfseries ] at ($ (current~page.south~east)+(0,.5*\l__time_vunit_dim) $) {#1}; } \endinput