% 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 }