[Tex/LaTex] create a framed environment for a margin note

framedmacrosmarginnote

What am trying to achieve is the following:

enter image description here

Of course, if this can be done so that there is a switch between even and odd pages. Currently I am only interested in the not appearing on the LHS margin. I currently do not have a MWE but I am throwing out the question. Probably you can start from here:

\documentclass[letterpaper]{article}
\usepackage[dvipsnames]{xcolor}
\usepackage{marginnote}
\usepackage{etoolbox}
\usepackage{calc}

\makeatletter
\patchcmd{\@mn@margintest}{\@tempswafalse}{\@tempswatrue}{}{}
\patchcmd{\@mn@margintest}{\@tempswafalse}{\@tempswatrue}{}{}
\reversemarginpar
\makeatother

\setlength{\marginparwidth}{2in}

\oddsidemargin 2in

\def\fbx#1{\vbox{\hbox{\hbox{#1}\setbox0\lastbox\copy0\kern\fboxsep\vrule width\fboxrule depth\dimexpr \fboxsep+\dp0\relax}%
            \hrule height\fboxrule}} 

\newcommand\caution[1]{%
\renewcommand*{\raggedleftmarginnote}{}
\relax\leavevmode\marginnote{%
        {\sffamily\bfseries\textcolor{BrickRed}{Caution!}}\\[1pt]%
        \fbx{\parbox[t]{\dimexpr\linewidth-3\marginparsep\relax}{#1}}%
    }
}
\begin{document}
test \caution{some random text for testing caution frame}. some random text some random text some random text some random text some random text.
\end{document}

enter image description here

Best Answer

Here's one possibility using the mdframed package and \marginnote from the marginnote package:

\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{marginnote}
\usetikzlibrary{calc}
\usepackage{lipsum}

\reversemarginpar

\newsavebox\mybox
\newlength\BoxHt

\newcommand\caution[2][-2.2\baselineskip]{%
\begin{lrbox}{\mybox}
\parbox{\marginparwidth}{#2}
\end{lrbox}%
\settoheight\BoxHt{\usebox\mybox}%
\raisebox{\BoxHt}[0pt][0pt]{\marginnote{%
  \begin{mdframed}[
    userdefinedwidth=\marginparwidth,
    innerleftmargin=3pt,
    innerrightmargin=3pt,
    linecolor=BrickRed,
    frametitle=\colorbox{white}{\space Caution\space},
    frametitlefont=\color{BrickRed}\sffamily,
    innertopmargin=10pt,
    frametitleaboveskip=-\ht\strutbox,
    frametitlebelowskip=-\ht\strutbox,
    frametitlealignment=\raggedright,
    singleextra={\fill[BrickRed] let \p1=(P), \p2=(O)  in 
    ( $ (P|-0,0.5*\y2+0.5*\y1) + (0,-4pt) $ ) -- +(4pt,4pt) -- +(0,8pt) -- cycle;}
]\RaggedRight\small#2\end{mdframed}}[#1]}}

\begin{document}

\lipsum*[3-4]\caution{\lipsum[2]}\lipsum[3-5]

Some test text\caution{Some text goes here just to illustrate the command}

\end{document}

enter image description here

A zoomed image:

enter image description here

The optional argument for \caution allows you to control the vertical shifting if necessary.

And here's another simpler option (which I personally like more) using tikz (and tikzpagenodes):

\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}

\newcounter{mycaution}

\newcommand\tikzmark[1]{%
  \tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}
\newcommand\caution[1]{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=BrickRed,anchor=east,xshift=-\marginparsep]   
  (mybox\themycaution)
  at ([yshift=3pt]current page text area.west|-\themycaution) 
  {\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#1}};
\node[fill=white,font=\color{BrickRed}\sffamily,anchor=west,xshift=7pt]
  at (mybox\themycaution.north west) {\ Caution!\ };
\fill[BrickRed]
  ([yshift=3pt]mybox\themycaution.east) --
  ([xshift=3pt]mybox\themycaution.east) --
  ([yshift=-3pt]mybox\themycaution.east) -- cycle;
\end{tikzpicture}%
}

\begin{document}

\lipsum*[3-4]\caution{\lipsum[2]}\lipsum[3-5]

Some test text\caution{Some text goes here just to illustrate the command}

\end{document}

enter image description here

And a zoomed image:

enter image description here

An improved version; now there's an optional argument allowing you to change the position of the box and of the pointer; possible values are b, t, and c, to place the pointer at the bottom, at the top, and at the center, respectively, of the box:

\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}

\newcounter{mycaution}
\newcommand\pointeranchor{}
\newcommand\boxanchor{}
\newlength\boxvshift
\newlength\uppertrianglecorner

\newcommand\tikzmark[1]{%
  \tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}

\newcommand\caution[2][c]{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\if#1b\relax
\renewcommand\pointeranchor{mybox\themycaution.south east}%
\renewcommand\boxanchor{south east}%
\setlength\boxvshift{-10pt}%
\setlength\uppertrianglecorner{13pt}%
\else
\if#1t\relax
\renewcommand\pointeranchor{mybox\themycaution.north east}%
\renewcommand\boxanchor{north east}%
\setlength\boxvshift{10pt}%
\setlength\uppertrianglecorner{-7pt}%
\else
\if#1c\relax
\renewcommand\pointeranchor{mybox\themycaution.east}%
\renewcommand\boxanchor{east}%
\setlength\boxvshift{0pt}%
\setlength\uppertrianglecorner{3pt}%
\fi\fi\fi%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=BrickRed,anchor=\boxanchor,xshift=-\marginparsep,yshift=\boxvshift]   
  (mybox\themycaution)
  at ([yshift=3pt]current page text area.west|-\themycaution) 
  {\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#2}};
\node[fill=white,font=\color{BrickRed}\sffamily,anchor=west,xshift=7pt]
  at (mybox\themycaution.north west) {\ Caution!\ };
\fill[BrickRed]
  ([yshift=\uppertrianglecorner]\pointeranchor) --
  ([yshift=\uppertrianglecorner-3pt,xshift=3pt]\pointeranchor) --
  ([yshift=\uppertrianglecorner-6pt]\pointeranchor) -- cycle;
\end{tikzpicture}%
}

\newcommand\Test{Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante. Phasellus adipiscing
semper elit.}

\begin{document}

\lipsum*[4]\caution[t]{\Test}\lipsum[3]\par\bigskip

\lipsum*[4]\caution{\Test}\lipsum[3]\par\bigskip

\lipsum*[4]\caution[b]{\Test}\lipsum[3]

\end{document}

enter image description here

The t option is useful if the box will appear in the first lines of the text area; b can be used in case the box will appear near the bottom of the text area.

A little variation required in a comment; now \caution has three optional arguments and a mandatory one:

\caution[<pos>][<color>][<title>]{<text>}

where ias an in the code immediately before, and can be b, t, or c (default=c); <color> controls the color used for the frame and title (default=BrickRed); <title> changes the title used for the frame (defualt=Caption!); <text> is the content of the note.

\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage{xparse}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}

\newcounter{mycaution}
\newcommand\pointeranchor{}
\newcommand\boxanchor{}
\newlength\boxvshift
\newlength\uppertrianglecorner

\newcommand\tikzmark[1]{%
  \tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}

\NewDocumentCommand{\caution}{O{c}O{BrickRed}O{Caution!}m}{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\if#1b\relax
\renewcommand\pointeranchor{mybox\themycaution.south east}%
\renewcommand\boxanchor{south east}%
\setlength\boxvshift{-10pt}%
\setlength\uppertrianglecorner{13pt}%
\else
\if#1t\relax
\renewcommand\pointeranchor{mybox\themycaution.north east}%
\renewcommand\boxanchor{north east}%
\setlength\boxvshift{10pt}%
\setlength\uppertrianglecorner{-7pt}%
\else
\if#1c\relax
\renewcommand\pointeranchor{mybox\themycaution.east}%
\renewcommand\boxanchor{east}%
\setlength\boxvshift{0pt}%
\setlength\uppertrianglecorner{3pt}%
\fi\fi\fi%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=#2,anchor=\boxanchor,xshift=-\marginparsep,yshift=\boxvshift]   
  (mybox\themycaution)
  at ([yshift=3pt]current page text area.west|-\themycaution) 
  {\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#4}};
\node[fill=white,font=\color{#2}\sffamily,anchor=west,xshift=7pt]
  at (mybox\themycaution.north west) {\ #3\ };
\fill[#2]
  ([yshift=\uppertrianglecorner]\pointeranchor) --
  ([yshift=\uppertrianglecorner-3pt,xshift=3pt]\pointeranchor) --
  ([yshift=\uppertrianglecorner-6pt]\pointeranchor) -- cycle;
\end{tikzpicture}%
}

\newcommand\Test{Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante. Phasellus adipiscing
semper elit.}

\begin{document}

\lipsum*[4]\caution[t]{\Test}\lipsum[3]\par\bigskip

\lipsum*[4]\caution[c][cyan!80!black]{\Test}\lipsum[3]\par\bigskip

\lipsum*[4]\caution[b][orange][Defcon 5!]{\Test}\lipsum[3]

\end{document}

enter image description here