commit e2aee201efe2ccee6bdc34554d1e3da5cd48a589 Author: Jeltz Date: Tue Aug 15 19:52:29 2023 +0200 Initial commit diff --git a/note.cls b/note.cls new file mode 100644 index 0000000..3086fa9 --- /dev/null +++ b/note.cls @@ -0,0 +1,977 @@ +% vim: ft=tex ts=2 sts=2 sw=2 et: +\NeedsTeXFormat{LaTeX2e} + +\ProvidesExplClass{note}{2023/07/15}{1.0}{Note} + + +%%% Class + +\RequirePackage { l3keys2e } +\LoadClass [ english, french, 11pt ] { article } + + +%%% Error messages + +% https://github.com/latex3/latex3/issues/887 +\prop_gput:Nnn \g_msg_module_type_prop { note } { Class } + +\msg_new:nnn { note } { Not~LuaLaTeX } + { Please ~ use ~ LuaLaTeX. } + + +%%% Constants + +%% Dimensions + +% Height of the page header +\dim_const:Nn \c__note_head_height_dim { 6.5mm } + +% Spacing between logos in the page header +\dim_const:Nn \c__note_logos_sep_dim + { \c__note_head_height_dim / 2} + +% Spacing between the page header and body +\dim_const:Nn \c__note_head_sep_dim { 8.5mm } + +% Skip between the page footer and body +\dim_const:Nn \c__note_foot_skip_dim + { \c__note_head_height_dim + \c__note_head_sep_dim } + +% Margin around {body + footer + header} +\dim_const:Nn \c__note_margin_dim { 33mm } + +% Left margin of list items +\dim_const:Nn \c__note_list_left_margin_dim + { 8.5mm } + +%% Skips + +% Spacing between heading number and text +\skip_const:Nn \c__note_heading_sep_skip { .5em } + +% Spacing between list item and label +\skip_const:Nn \c__note_list_label_sep_skip + { \c__note_heading_sep_skip } + +% Parskip +\skip_const:Nn \c__note_par_skip + { 9pt plus 3pt minus 2pt } + +% Parindent +\skip_const:Nn \c__note_par_indent_skip { 0pt } + +% Section +\skip_const:Nn \c__note_section_skip + { ( \c__note_par_skip * 150 ) / 100 } + +% Subsection +\skip_const:Nn \c__note_subsection_skip + { ( \c__note_par_skip * 135 ) / 100 } + +% Subsubsection +\skip_const:Nn \c__note_subsubsection_skip + { ( \c__note_par_skip * 120 ) / 100 } + +% Total spacing between successive list items +\skip_const:Nn \c__note_list_total_item_sep_skip + { \c__note_par_skip / 2 } + +% Spacing between paragraphs inside a single list item +\skip_const:Nn \c__note_list_par_sep_skip + { \c__note_par_skip / 4 } + +% Spacing between footnote mark and text +\skip_const:Nn \c__note_footnote_mark_sep_skip + { \c__note_par_skip / 4 } + +%% Strings + +% Separator between title and subtitle in PDF infos +\str_const:Nn \c__note_title_sep_str { ~ — ~ } + + +%%% Declarations + +\tl_new:N \g__note_subtitle_tl +\tl_new:N \g__note_date_tl +\tl_new:N \g__note_author_tl +\tl_new:N \g__note_reference_tl +\tl_new:N \g__note_place_tl +\tl_new:N \g__note_sender_title_tl +\tl_new:N \g__note_recipient_title_tl +\tl_new:N \g__note_plaintiff_tl +\tl_new:N \g__note_defendant_tl +\tl_new:N \g__note_court_prefix_tl +\tl_new:N \g__note_court_tl +\tl_new:N \l__note_meta_title_tl +\tl_new:N \l__note_meta_author_tl +\tl_new:N \l__note_sigs_flush_tl + +\seq_new:N \g__note_logos_url_seq +\seq_new:N \g__note_logos_seq +\seq_new:N \g__note_sigs_name_seq +\seq_new:N \g__note_sigs_title_seq +\seq_new:N \g__note_sender_addr_seq +\seq_new:N \g__note_recipient_addr_seq + +\int_new:N \g__note_logos_map_int +\int_new:N \g__note_sigs_map_int + +\box_new:N \l__note_logos_box +\box_new:N \l__note_date_box + +\bool_new:N \g__note_show_head_bool + + +%%% Common variants + +\cs_generate_variant:Nn \exp_args:Nnnx { cnnx } +\cs_generate_variant:Nn \exp_args:Nnnn { cnnn } + + +%%% Basic checks + +\sys_if_engine_luatex:F + { \msg_fatal:nn { note } { Not ~ LuaLaTeX } } + + +%%% Options + +\keys_define:nn { note/options } + { + nm .str_set:N = \g__note_mode_str, + nm .default:n = { note }, + } + +\ProcessKeysOptions { note/options } + +\bool_gset:Nn \g__note_show_head_bool + { + \str_case:VnF \g__note_mode_str + { + { letter } { \c_false_bool } + { brief } { \c_false_bool } + } + { \c_true_bool } + } + + +%%% Packages + +\RequirePackage { fontspec } +\RequirePackage { xparse } +\RequirePackage [ latin, english, french ] { babel } +\RequirePackage [ babel ] { csquotes } +\RequirePackage { enumitem } +\RequirePackage { fancyhdr } +\RequirePackage [ explicit ] { titlesec } +\RequirePackage [ svgnames ] { xcolor } +\RequirePackage { graphicx } +\RequirePackage { acro } +\RequirePackage { geometry } +\RequirePackage { parskip } +\RequirePackage { tabularx } +\RequirePackage { siunitx } +\RequirePackage { booktabs } +\RequirePackage [ avoid-all ] { widows-and-orphans } +\RequirePackage [ babel = true ] { microtype } +\RequirePackage { hyperref } + + +%%% Colors + +\definecolor { note/red } { HTML } { cd1e27 } +\definecolor { note/dark-blue } { HTML } { 44589f } %4e5368 } +\definecolor { note/light-blue } { HTML } { 729fcf } + + +%%% Geometry + +\geometry + { + %showframe, + centering, + a4paper, + headheight = \c__note_head_height_dim, + headsep = \c__note_head_sep_dim, + footskip = \c__note_foot_skip_dim, + margin = \c__note_margin_dim, + includehead, + includefoot, + } + +\bool_if:NF \g__note_show_head_bool + { + \geometry + { + headheight = 0pt, + headsep = 0pt, + } + } + + +%%% Paragraphs + +\skip_set_eq:NN \parindent \c__note_par_indent_skip +\skip_set_eq:NN \parskip \c__note_par_skip + + +%%% Babel + +\AddBabelHook { * } { foreign } + { \em } + +\frenchsetup + { + ListItemsAsPar = true, + FrenchFootnotes = true, + } + + +%%% Lists + +% TODO fix the skip v. dim mess +\SetEnumitemKey { note/spacing } + { + itemsep = + \skip_eval:n + { + \c__note_list_total_item_sep_skip + - \c__note_list_par_sep_skip + }, + parsep = \skip_use:N \c__note_list_par_sep_skip, + topsep = 0pt, + itemindent = 0pt, + listparindent = 0pt, + leftmargin = \skip_use:N \c__note_list_left_margin_dim, + labelsep = \skip_use:N \c__note_list_label_sep_skip, + } + +\setlist [ enumerate ] { note/spacing } + +\setlist [ enumerate, 1 ] + { + label = \textcolor { note/dark-blue } { \sffamily \arabic*. }, + } + +\setlist [ itemize ] { note/spacing } + +\setlist [ itemize, 1 ] + { + label = \textcolor { note/dark-blue } { \sffamily \textbullet }, + } + + +%%% Hyperref + +\hypersetup + { + colorlinks, + urlcolor = RoyalBlue, + linkcolor = note/red ! 80 ! black, %VioletRed, + } + +\AddToHook { begindocument/before } + { + \group_begin: + \tl_set:Nn \l__note_meta_title_tl + { + \@title + \tl_if_empty:NF \g__note_subtitle_tl + { + \str_use:N \c__note_title_sep_str + \tl_use:N \g__note_subtitle_tl + } + } + \tl_set:Nx \l__note_meta_author_tl + { + \tl_if_empty:NTF \g__note_author_tl + { \seq_use:Nn \g__note_sigs_name_seq { , ~ } } + { \g__note_author_tl } + } + \hypersetup + { + pdftitle = { \tl_use:N \l__note_meta_title_tl }, + pdfauthor = { \tl_use:N \l__note_meta_author_tl }, + } + \group_end: + } + + +%%% Headings + +\setcounter { secnumdepth } { 5 } + +%% Section + +\titleformat { \section } + [ block ] + { + \sffamily \Large \bfseries + \color { note/dark-blue } + } + { \Roman { section } . } + { \skip_use:N \c__note_heading_sep_skip } + {#1} + +\titlespacing \section + { 0pt } + { \skip_use:N \c__note_section_skip } + { \skip_use:N \c__note_section_skip } + +\tl_gset:Nn \thesection + { \Roman { section } } + +%% Subsection + +\titleformat { \subsection } + [ block ] + { + \sffamily \large \bfseries + \color { note/dark-blue } + } + { \Alph { subsection } . } + { \skip_use:N \c__note_heading_sep_skip } + {#1} + +\titlespacing \subsection + { 0pt } + { \skip_use:N \c__note_subsection_skip } + { \skip_use:N \c__note_subsection_skip } + +\tl_gset:Nn \thesubsection + { \thesection . \Alph { subsection } } + +%% Subsubsection + +\titleformat { \subsubsection } + [ block ] + { + \sffamily \normalsize \bfseries + \color { note/dark-blue } + } + { \arabic { subsubsection } . } + { \skip_use:N \c__note_heading_sep_skip } + {#1} + +\titlespacing \subsubsection + { 0pt } + { \skip_use:N \c__note_subsubsection_skip } + { \skip_use:N \c__note_subsubsection_skip } + +\tl_gset:Nn \thesubsubsection + { \thesubsection . \arabic { subsubsection } } + +%% Paragraph + +\titleformat { \paragraph } + [ runin ] + { + \sffamily \normalsize %\bfseries + \color { note/dark-blue } + } + {} + { 0pt } + %{ \alph { paragraph } . } + %{ \skip_use:N \c__note_heading_sep_skip } + {#1} + +\titlespacing \paragraph + { 0pt } + { \skip_use:N \c__note_par_skip } + { \skip_use:N \c__note_heading_sep_skip } + + +%%% Fonts + +\setmainfont { Libertinus Serif } +\setsansfont { Libertinus Sans } +\setmonofont { Fira Mono } + [ Scale = 0.84 ] + + +%%% Siunitx + +% TODO babel +\sisetup + { + detect-all, + locale = FR, + } + +\DeclareSIUnit \euro {€} + + +%%% Quotes FIXME + +\cs_set:Npn \mktextquote #1#2#3#4#5#6 + { #1 { \em #2 } #3 #6 #4 #5 } + +\cs_set:Npn \mktextins #1 + { { \em [ #1 ] } } + +\cs_set:Npn \mkblockquote #1#2#3#4 + { + \openautoquote { \em #1 } \closeautoquote #2 #4 #3 + } + +\cs_set:Npn \mktextelp + { \mktextins { ... } } + +\NewDocumentEnvironment { block } {} + { + \group_begin: + \begin { list } {} + { + \setlength{\topsep}{0pt} + \setlength{\leftmargin}{4.25mm} + \setlength{\rightmargin}{0pt} + \setlength{\listparindent}{\parindent} + \setlength{\itemindent}{\parindent} + \setlength{\parsep}{\parskip} + \@beginparpenalty=10000 + } + \item[] + } + { + \end { list } + \group_end: + } + +\SetBlockEnvironment { block } + +\DeclareQuoteStyle [ guillemets ] { french } + [ \initfrenchquotes ] + { \mkfrenchopenquote { \guillemotleft } } + [ { \em \mkfrenchopenquote { \guillemotleft } } ] + { \mkfrenchclosequote { \guillemotright } } + { \mkfrenchopenquote { \textquotedblleft } } + [ { \em \mkfrenchopenquote { \textquotedblleft } } ] + { \mkfrenchclosequote { \textquotedblright } } + + +%%% Headers and footers + +\cs_new:Nn \__note_logos_map_indexed_inline:n + { + \int_gincr:N \g__note_logos_map_int + \cs_gset:cn + { __note_logos_map_ \int_use:N \g__note_logos_map_int :nnn } + { #1 } + \seq_map_indexed_inline:Nn \g__note_logos_seq + { + \exp_args:cnnx + { __note_logos_map_ \int_use:N \g__note_logos_map_int :nnn } + {##1} % index + {##2} % image path + { \seq_item:Nn \g__note_logos_url_seq {##1} } % url + } + } + +\cs_new:Nn \__note_logos_include:nn + { + \__note_logos_map_indexed_inline:n + { + \int_compare:nNnT {##1} > {1} + { \skip_horizontal:n {#2} } + \tl_if_empty:nF {##3} + { \href {##3} } + { \includegraphics [ height = #1 ] {##2} } + } + } + +\fancypagestyle { fancyplain } + { + \fancyhf {} + \bool_if:NT \g__note_show_head_bool + { + % TODO l3box + \fancyhead [R] + { + \parbox [] [ \headheight ] [c] { .5 \textwidth } + { + \raggedleft \sffamily + \tl_if_empty:NTF \g__note_date_tl + { \today } + { \tl_use:N \g__note_date_tl } + } + } + \fancyhead [L] + { + \parbox [] [ \headheight ] [c] { .5 \textwidth } + { + \__note_logos_include:nn + { \c__note_head_height_dim } + { \c__note_logos_sep_dim } + } + } + } + \fancyfoot [C] { \sffamily \thepage } + \tl_set:Nn \headrulewidth { 0pt } + \tl_set:Nn \footrulewidth { 0pt } + } + +\pagestyle { fancyplain } + + +%%% Preamble + +\cs_new:Nn \__note_undef_begin:N + { + \AddToHook { begindocument/before } + { \cs_undefine:N #1 } + } + +\DeclareDocumentCommand \author {m} + { \tl_set:Nn \g__note_author_tl {#1} } + +\__note_undef_begin:N \author + +\DeclareDocumentCommand \reference {m} + { \tl_set:Nn \g__note_reference_tl {#1} } + +\__note_undef_begin:N \reference + +\NewDocumentCommand \subtitle {m} + { \tl_set:Nn \g__note_subtitle_tl {#1} } + +\__note_undef_begin:N \subtitle + +\NewDocumentCommand \place {m} + { \tl_set:Nn \g__note_place_tl {#1} } + +\__note_undef_begin:N \place + +\NewDocumentCommand \plaintiff {m} + { \tl_set:Nn \g__note_plaintiff_tl {#1} } + +\__note_undef_begin:N \plaintiff + +\NewDocumentCommand \defendant {m} + { \tl_set:Nn \g__note_defendant_tl {#1} } + +\__note_undef_begin:N \defendant + +\NewDocumentCommand \court {O{}m} + { + \tl_set:Nn \g__note_court_prefix_tl {#1} + \tl_set:Nn \g__note_court_tl {#2} + } + +\__note_undef_begin:N \court + +\DeclareDocumentCommand \date {m} + { \tl_set:Nn \g__note_date_tl {#1} } + +\__note_undef_begin:N \date + +\NewDocumentCommand \addlogo {O{}m} + { + \seq_put_right:Nn \g__note_logos_url_seq {#1} + \seq_put_right:Nn \g__note_logos_seq {#2} + } + +\__note_undef_begin:N \addlogo + +\cs_new:Nn \__note_sender_addr_add:n + { \seq_put_right:Nn \g__note_sender_addr_seq {#1} } + +\cs_new:Nn \__note_recipient_addr_add:n + { \seq_put_right:Nn \g__note_recipient_addr_seq {#1} } + +\NewDocumentCommand \sender {m>{\SplitList{,}}m} + { + \tl_set:Nn \g__note_sender_title_tl {#1} + \ProcessList {#2} { \__note_sender_addr_add:n } + } + +\__note_undef_begin:N \sender + +\NewDocumentCommand \recipient {m>{\SplitList{,}}m} + { + \tl_set:Nn \g__note_recipient_title_tl {#1} + \ProcessList {#2} { \__note_recipient_addr_add:n } + } + +\__note_undef_begin:N \recipient + +%%% Titlepage + +\cs_new:Nn \__note_title_note_show: + { + \begin { center } + \vspace* { 2.65em } + { + \sffamily \LARGE \bfseries + \color { note/dark-blue } + \@title + } + \tl_if_empty:NF \g__note_subtitle_tl + { + \par + \sffamily \Large + \tl_use:N \g__note_subtitle_tl + } + \vspace* { 2.65em } + \end { center } + } + +\cs_new:Nn \__note_title_letter_show: + { + \begin { flushleft } + \parbox { .40 \textwidth } + { + \flushleft \sffamily + \textbf { \tl_use:N \g__note_sender_title_tl } + \vspace* {.25em} + \par \seq_use:Nn \g__note_sender_addr_seq { \\ } + } + \end { flushleft } + \vspace* { 1em } + \begin { flushright } + \parbox { .45 \textwidth } + { + \flushleft \sffamily + \textbf { \tl_use:N \g__note_recipient_title_tl } + \vspace* {.25em} + \par \seq_use:Nn \g__note_recipient_addr_seq { \\ } + } + \end { flushright } + \vspace* { 2em } + \begin {flushright} + \parbox { .45 \textwidth } + { + \flushleft \sffamily + \tl_if_empty:NTF \g__note_place_tl + { Le ~ } + { \tl_use:N \g__note_place_tl , ~ le ~ } + \tl_if_empty:NTF \g__note_date_tl + { \today } + { \tl_use:N \g__note_date_tl } + } + \end { flushright } + \vspace* { 4.5em } + \group_begin: + \sffamily + \textcolor { note/dark-blue } { \bfseries Objet ~ : } + \hspace { 1em } + \@title \par + \tl_if_empty:NF \g__note_reference_tl + { + \textcolor { note/dark-blue } { \bfseries Réf. ~ : } + \hspace { 1em } + \tl_use:N \g__note_reference_tl + } + \group_end: + \vspace*{1.5em} + } + +\cs_new:Nn \__note_title_brief_show: + { + \pagenumbering { Alph } + \begin { titlepage } + \vspace* { 13.5mm } + \begin { flushleft } + \begin { minipage } { .8 \textwidth } + \begin { flushleft } + \color { note/dark-blue } + \sffamily \bfseries \Huge \@title + \end { flushleft } + \tl_if_empty:NF \g__note_reference_tl + { + \vspace* { 2.5mm } + \begin { flushleft } + \LARGE \normalfont \sffamily + Dossier ~ \no \g__note_reference_tl + \end { flushleft } + } + \end { minipage } + \end { flushleft } + \vspace { 12.5mm } + \begin { flushright } + \tl_if_empty:NF \g__note_court_prefix_tl + { + \sffamily \large \g__note_court_prefix_tl + \par + } + \LARGE \g__note_court_tl + \end { flushright } + \vspace { \fill } + \begin { center } + \color { note/dark-blue } + \sffamily \bfseries \Large Pour + \vspace* { 2.5mm } + \end { center } + \begin { center } + \begin { minipage } { .8 \textwidth } + \large \sffamily \g__note_plaintiff_tl + \end { minipage } + \end { center } + \vspace { 11.5mm } + \begin { center } + \color { note/dark-blue } + \sffamily \bfseries \Large Contre + \vspace* { 2.5mm } + \end { center } + \begin { center } + \begin { minipage } { .8 \textwidth } + \large \sffamily \g__note_defendant_tl + \end { minipage } + \end { center } + \vspace* { 13.5mm } + \end { titlepage } + \pagenumbering { arabic } + } + +\DeclareDocumentCommand \maketitle {} + { + \str_case:VnF \g__note_mode_str + { + { letter } { \__note_title_letter_show: } + { brief } { \__note_title_brief_show: } + } + { \__note_title_note_show: } + } + + +%%% Mail + +\NewDocumentCommand \email {m} + { \href { mailto \c_colon_str #1 } { #1 } } + + +%%% Eur-Lex + +\cs_new:Nn \__note_eurlex_lang:N + { + \str_case:VnF #1 + { + { french } { FR } + } + { EN } + } + +\cs_new:Nn \__note_eurlex_uri:Nn + { + % https://tex.stackexchange.com/q/384826 + https \c_colon_str //eur-lex.europa.eu/legal-content/ + \__note_eurlex_lang:N #1 /TXT/?uri = #2 + } + +\NewDocumentCommand \eurlex {mm} + { + \href + { \__note_eurlex_uri:Nn \languagename {#1} } + {#2} + } + + +%%% JORF + +\cs_new:Nn \__note_jorf_uri:n + { https \c_colon_str //www.legifrance.gouv.fr/jorf/id/ #1 } + +\NewDocumentCommand \jorf {mm} + { + \href + { \__note_jorf_uri:n {#1} } + {#2} + } + + +%%% BOFiP + +% TODO date +\cs_new:Nn \__note_bofip_uri:n + { https \c_colon_str //bofip.impots.gouv.fr/doctrine/ #1 } + +\NewDocumentCommand \bofip {m} + { \href { \__note_bofip_uri:n {#1} } {#1} } + +%%% Articles + +\DeclareExpandableDocumentCommand \art {m} + { + \texorpdfstring { \nolinebreak } {} + \mbox {#1} + } + +\clist_map_inline:nn + { + bis, ter, quater, quinquies, + sexies, septies, octies, nonies + } + { + \exp_args:Nc \DeclareExpandableDocumentCommand {#1} {m} + { \art { ##1 ~ \lat {#1} } } + } + +\DeclareExpandableDocumentCommand \para {m} + { § \nobreakspace \mbox { #1 } } + +\DeclareExpandableDocumentCommand \rn {m} + { \art { \int_to_Roman:n {#1} } } + +\DeclareExpandableDocumentCommand \ao {m} + { \art { #1 \up { o } } } + +\DeclareExpandableDocumentCommand \L {m} + { \art { L. \, #1 } } + +\DeclareExpandableDocumentCommand \R {m} + { \art { R. \, #1 } } + + +%%% Names + +\DeclareExpandableDocumentCommand \name {om} + { + \IfValueT {#1} { #1 ~ } + \textsc {#2} + } + +\cs_new:Nn \__note_name_prefix_translate:n + { + \str_case:nnF {#1} + { + { m } { M. } + { mm } { MM. } + { mme } { M \up { me } } + { mmes } { M \up { mes } } + { me } { M \up { e } } + } + {#1} + } + +\clist_map_inline:nn { m, mm, mme, mmes } + { + \exp_args:Nc \DeclareExpandableDocumentCommand {#1} {om} + { + \__note_name_prefix_translate:n {#1} + \nobreakspace + \IfValueTF {##1} + { \name [##1] {##2} } + { \name {##2} } + } + } + + +%%% Todo + +\NewDocumentCommand \todo {m} + { \textcolor { note/red } { [ #1 ] } } + + +%%% Foreign language shortcuts + +\NewExpandableDocumentCommand \en {m} + { \foreignlanguage { english } {#1} } + +\NewExpandableDocumentCommand \lat {m} + { \foreignlanguage { latin } {#1} } + + +%%% End of page + +\NewDocumentEnvironment { endofpage } {} + { \vfill } + {} + + +%%% Footnotes + +\AddToHook { begindocument } + { + \cs_gset:Npn \@makefntext #1 + { + \textcolor { note/dark-blue } { \sffamily \@thefnmark . } + \skip_horizontal:N \c__note_footnote_mark_sep_skip + #1 + } + % FIXME + \cs_gset:Npn \footnoterule + { + \kern -3pt + \textcolor { note/dark-blue } + { \rule { .25 \textwidth } { .75pt } } + \vspace { .5em } + } + } + + +%%% Signatories + +\cs_new:Nn \__note_sigs_add:nn + { + \seq_put_right:Nn \g__note_sigs_name_seq {#1} + \seq_put_right:Nn \g__note_sigs_title_seq {#2} + } + +\cs_new:Nn \__note_sigs_map_indexed_inline:n + { + \int_gincr:N \g__note_sigs_map_int + \cs_gset:cn + { __note_sigs_map_ \int_use:N \g__note_sigs_map_int :nnn } + { #1 } + \seq_map_indexed_inline:Nn \g__note_sigs_name_seq + { + \exp_args:cnnx + { __note_sigs_map_ \int_use:N \g__note_sigs_map_int :nnn } + {##1} % index + {##2} % name + { \seq_item:Nn \g__note_sigs_title_seq {##1} } % title + } + } + +\DeclareDocumentCommand \signature {O{}m} + { \__note_sigs_add:nn {#2} {#1} } + +\DeclareDocumentCommand \makesignatures {s} + { + \vspace* { 3em } + \IfBooleanT {#1} + { + \tl_if_empty:NTF \g__note_place_tl + { Le ~ } + { Fait ~ à ~ \tl_use:N \g__note_place_tl , ~ le ~ } + \tl_if_empty:NTF \g__note_date_tl + { \today } + { \tl_use:N \g__note_date_tl } . + \vspace* { 1em } + } + \__note_sigs_map_indexed_inline:n + { + \group_begin: + \tl_set:Nx \l__note_sigs_flush_tl + { + \int_compare:nNnTF { \int_mod:nn {##1} { 2 } } = { 1 } + { flushright } + { flushleft } + } + \begin { \tl_use:N \l__note_sigs_flush_tl } + \parbox { .5 \textwidth } + { + \centering + \textsc {##2} + \tl_if_empty:nF {##3} + { + , \\ + \textit { ##3 } + } + } + \end { \tl_use:N \l__note_sigs_flush_tl } + \group_end: + } + } + +\DeclareDocumentCommand \opening {m} + { + #1 + \vspace* { 1em } + } + +\DeclareDocumentCommand \closing {m} + { + \vspace* { 1em } + #1 + }