From ffabd050ccba621fe87e8be7daa3bcb2d59b4b63 Mon Sep 17 00:00:00 2001 From: Igor Fedoronchuk Date: Tue, 13 Oct 2026 15:00:16 +0200 Subject: [PATCH] Theme the Trix / ActionText editor in light and dark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trix ships with ActionText (a Rails built-in), so every ActiveAdmin app can have a rich-text field. Theme its chrome — toolbar, editor surface, link dialog, content pre/blockquote — off the --aa-* tokens so it follows the palette in both modes. Trix bakes its toolbar icons into the base CSS as black SVGs, so invert them in dark mode to keep them legible. The app still imports Trix's own base CSS; these rules only restyle it and are inert when no editor is present. Adds a Rich-text demo page to the dummy app plus a screenshot task producing img/trix-{light,dark}.png. --- .../stylesheets/wigu/active_admin_theme.scss | 55 ++++++++++++++++++ img/trix-dark.png | Bin 0 -> 18152 bytes img/trix-light.png | Bin 0 -> 17866 bytes test/dummy/app/admin/editor.rb | 24 ++++++++ .../app/assets/javascripts/active_admin.js | 1 + .../app/assets/stylesheets/active_admin.scss | 1 + test/dummy/config/application.rb | 8 +++ test/trix_screenshot.rb | 32 ++++++++++ 8 files changed, 121 insertions(+) create mode 100644 img/trix-dark.png create mode 100644 img/trix-light.png create mode 100644 test/dummy/app/admin/editor.rb create mode 100644 test/trix_screenshot.rb diff --git a/app/assets/stylesheets/wigu/active_admin_theme.scss b/app/assets/stylesheets/wigu/active_admin_theme.scss index dd4761d..f9306d8 100644 --- a/app/assets/stylesheets/wigu/active_admin_theme.scss +++ b/app/assets/stylesheets/wigu/active_admin_theme.scss @@ -1959,3 +1959,58 @@ input[type='radio'] { html:not([data-theme="light"]) { @include aa-dark-content; } } html[data-theme="dark"] { @include aa-dark-content; } + +// Trix / ActionText editor. Trix ships with ActionText (a Rails built-in), so +// its chrome is themed here for every consumer; the app still imports Trix's +// own base CSS (trix/dist/trix). All rules key off the --aa-* tokens, so they +// follow the active palette in both light and dark, and are inert when no +// editor is on the page. +trix-toolbar { + .trix-button-group { border-color: var(--aa-border); } + .trix-button { + background: var(--aa-surface); + color: var(--aa-text); + border-bottom-color: var(--aa-border); + &:not(:first-child) { border-left-color: var(--aa-border); } + &:not(:disabled):hover { background: var(--aa-surface-hover); } + &.trix-active { background: var(--aa-selected); } + } + // Trix dims idle icons to opacity 0.6 and disabled ones to 0.125 — both read + // as faint in either palette, the 0.125 so faint the block-format buttons + // (disabled until the editor is focused) look broken. Lift idle to 0.8 and + // disabled to 0.4: still clearly dimmer than idle, but legible. Trix keeps the + // active icon at 1 via a higher-specificity rule. + .trix-button--icon::before { opacity: 0.8; } + .trix-button--icon:disabled::before { opacity: 0.4; } +} + +trix-editor { + background: var(--aa-input-bg); + border-color: var(--aa-input-border); + color: var(--aa-text); + &:empty:not(:focus)::before { color: var(--aa-text-muted); } // placeholder +} + +.trix-content { + pre { background: var(--aa-surface-2); } + blockquote { border-left: 0.3em solid var(--aa-border); } +} + +.trix-dialog { + background: var(--aa-surface); + color: var(--aa-text); + box-shadow: 0 2px 8px var(--aa-shadow); + input[type="text"], input[type="url"] { + background: var(--aa-input-bg); + border-color: var(--aa-input-border); + color: var(--aa-text); + } + .trix-button { background: var(--aa-accent); color: #fff; } +} + +// Trix bakes its toolbar icons into the base CSS as black SVG background images +// on ::before; invert them in dark mode so they read on the dark toolbar (the +// idle/disabled opacity lift above applies in both modes). +@include aa-dark { + trix-toolbar .trix-button--icon::before { filter: invert(1); } +} diff --git a/img/trix-dark.png b/img/trix-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d5c82d9fa4aed476440387f494fb702d65670782 GIT binary patch literal 18152 zcmb5WbyQo?w=Gv{0b91Pv0TNPu9$ z^_`aAz2l8>?|9?;@&_XcJ2{(u_L^(1x#lKJRapiHlN9sLojW*kvXbg|?mTbIF>aQOk%z?@cYOIFR`2|}x zguJb+g4rlV#It`djOtq2(#Pt&0j>=^M!4l6IaS%^<@tKKYG@(9bMK2sTs-4bQ&TqF zq#>i6x1*dagg&W$uv!;OEMD#q`lKTE&0s-K->_&3Npd@2gCkt+V3J70_+?$y(kvX# zJ2}O1`idP1A|2=iOv-EeBfK|Ew z81(PS9dfb8zsq#z&f>>!$b2=k?yxRXG*Ov!jqSPztn#A4h84d%JGL_TGqwAYqwCWUM2^bA2A6On>D$NNXN@ulg82J38IABp^~?oIli zFRj*7kWile&W+hcG+gxT@+dXgH-iIz6vfjsGc^;Gr)L;iE_kb?b%!5Rmwzc)Wj1nl zJu$faedQzE=KA8_CD}GT8ui+Dp2x~6c0sZhzXe^k3b%Ofc?${pUgYP$_T=@9lD?Qs zog$&6!4E4G%hN8>)6=6RB1%e1!ffhjt(LUEdvz~{T;7gTWTJXHxNt*91Y7~j7=FX` zwLS1ol(vDUEGk-ASyRl_#ihQg{>g$pP%py7I$-YWZ#QU9dYjjx%aLM-SeW;2nsKk=zLz~R9OE&n_%33y&%EC6E|@2e zf8=={QJtQ>?XK8`yOUFCMa6_o-R*jQRBPy**w2+aobBm}>Clps8(sQ!-*dqqG4~Kp z8w3*IZz5L^z~}t%RI6OO!l2FNh-@6)MV#qva@MbIi@aIzp`j5Tfcbpxw zygYr?iS$%6X^W`{oLkJ6lfg#X&YjA64mHQ1RQ2`ITf?GryuKo4*zb3CC|#P;nLz!< zUV002)rXK|M&~MF-kWpSBx}1c`ci>1GZQBYr=COKMo}cd4b`&?tF`tX`=ifj0LhS- z6HXC_RGx_H$)tRPBb!>AH@jxgJ28>r`A`0sTOkB}jdZPxf*}tDe{VTn?*=-y$2z}` zy4}HVmbXKQaB-CrbfU>cev6bAGUVDx>?2n}Q>xVhUhgZstEqFPV<6u(wY6;)NS+b0 z#>!%19^71Ssrc}DbkMH+j!q~|kYDw^@kP7YU{@HVk>j3->k4Z$Kbk7b z-2MFxC8i5zlOOz0urR!o}hH@q-wl^G2hJ0>hED1pM7pZr^!& zs*#rj$CmSgG9?qO7ei!@(5mL5rm*w&Y8PGQW8FvpcH?4@1E`$M>Skdc;c(v9YB4)0 z8iGhz++152o2y1{u@8Wn8k^KG;g?%6_K#BDj5;a3m+*%sj;9h`US8Ul+KXd+8RejB z;4ILn;eZ($&XcC4o$l_hOA4rV6r zuKzGLs1=3xY1q`k{o0KdL`KkrW);02cfI%NN3D(1Wo3Fg%W=r_*ECV!j=uguZ~r6AbCZf?ve-A911TDsuSt3Q zetrEi8j$bpRFjeq>)#Zz9duhtKaB~;Y&x8D)bkqtGqE(Rackn z4Ij%8f3?0(!sN{_Ab4?x5lJQ*2Di1f4GNM7L2$+S*tmyWEda1~Oho+eHs2{V3TB4B zRYS55YK8pCozfscPKg#4S09vdm%x+@`pm0+Er-nnzXZ$3)5aOj-Z*fQ1~Z>SQNsu{ z+68HKQr?c^xn5J#P#^1mwQ8jqlPc_(-OzASl}A&ck})vUtNwen)?>5wg@DIBpR4YQ zDdIotY7@2#K^Vc}Kf5a?K_KI^wCckU{w)!o8~bA0d6AVNx%dJCVxr5#tA+@$U&v&+ z{>4&@V?{RZ$zTS1O`TxC;bZP-O2MD=o$ zRvzN!=3X;?Lzg6bC}5a|r>d5#XsK_g)$0cS{MpP^BVN92GY>CuQIgu3xV`c=c{x0| z-(kjgF`zZY%`*z}Y$7nRLwEUf>hv<5AL=y8o{HgAN!;_-`41L}C9w zveliA+fjEgo|fOPI^Rd9hqoWR`-S=TEnJc|NiQ)k?EAMbq3<7qAW~-HqrJUJw5uCW-yb6gYfXwRK0vb2JwrFGt@#$Oi~j?3L*KpF)hA(qkNe* zc(BjXr+8O-2P*fxMYIXbe3>kyQ8bUxD4R}kE`w6>m^ zf1F^fD!UYJxaMI_ov0@zCFM4jomX26fg~c^+Q^ztUPn?1dL9c4dh93<|0aJ*%HcQ! z)hqK@FBks1e}8c2;;Cc>o+63QQA=ym@94N_z05n5E{>_peaf=3oVtoZpfVk8ef^X6 z6VcL&mBl{hDxF`iOB!xY-YsW$x(!`jaw>?62km_KzTib%|8V+qedfxjTc&pBzQ#yVr;0!&=%C zlSTvBnge-vG_4m8Hdaj>jpiuB)5qwIS>7j>EbO zhn~0`K~mwF1j&kgR4L1Y#)0+)67VIxVDZtFOPD9k$-?y8+-M3>HDkoykB&3_`fI6v zGwB$~zm&CcVRVM(YG|;W3^^lNa^mLtHTvSCBC_~h6;*rlt=Q=xu>F6d}tBQ*FU;Y4Vt4W*sG}@_;M?CvYVPIB8Ov8Y-rJlZyj++p_RPN{-s2EKTPWaLOK1UrF7uVSD8U7}& zYU_L0#OIp>MirugG7keqMUQEuWnx^=y$tyHr0&>W4$)c&QCJfCZ~8Gf4LVf+}0-I z;o)(Jp?z*F3ZpTt@|ydu#>0`8lM|PdV_K%IF!Sr@&rd@NpFe-beNAb~Hvw7-zitG$ zBO;aZ`XI1fjmw-*93v>e%F^YjLU#;V{F~)vka#c-`AD0Jvoq2P9QgC_YiP?XbBR$- z>JRqzYv}^`$-M6gE3ZmlZ?CU+7l({YD5M|60gBCqqM93wY!KIDY2Zp-9YlmL_L!hn z$>^Bq{o_{_tor)8N=jwwa`eB5ck#>|tw2VjP}s@c>{r*qw zxSNRa@$vcU@A2^~K(q{Hl+3m4irFdFmMKn}G<4+T>|DS7d>!$Wl(fU>sAuW-(2#OM zX>oBeRzx^EZ?#^ovVc!(3z%@AzyDfl(O^~jN}Az)kf%**y!|Vt|EAM7y908HN3NSQihy@0@U6b6gT0!8z^M+=P{E> zncrDmr%c>r>v45U%dA3)(O~~pykqWpLAt!4*|jPgub<7;|qz6k)Pe@b5oK2cT@X2r)u;_a`Md`_U=`!6kE!?BHCL*?w^ zqL&R_usJj{J9}~JmBAM~wnk)HODqzjLW6$jr=Y;r{;?5H)b(gN95lTeN@c)jayi{Y zBzo{CZvDFvfRp*nuRtIeYPu;c0NxN9@<5|ZwE%W?h`xC%d~}*4Q@DNFS7KY(yu7>1 zdv#oN*h#XRTe;npjK;$JUQ&`@zVxZUI6t`PxwLZ18xH1*y}_7v%gE%13(i}7`JTxS z<4Q~I1Wc>ms?{23>CVG#eyafypjYPb`x{@k&hRTmUWk>sp1!_D&e~fcbc=3fPA)YN zN@z5e@1AveNJuv#@J7R-Rq^eaBxYyE+L|TQh&@qWUr(Q(JjF&E1D7&qIS~wIznTf^ zjJAUjaSS0epLnZ!puUCK@F9E0c; zm8mLL>e!8PK}%Kl>Yk;(nO;T~yB`bw7}G*~6Cp}6F%)3F06P=4{d$z(^rCZOk>=(~ z5wi9vnMvb$RaH^2|8IlFm#T=Zv4_6H&JcBXmNQeNHWT;Uw{Lxta>7@06chrnva+wj zgH-c%zvf^oM$yqhgxe_E(_#8b-~SL3aQNqzmikTYK;7NR10TMySZqG`IqnVv{@gpD z!Ps0GlpVWv$wp)qa?ICO?VzZzu(rC|ym@%6Bd(a#p49phHS3uYSY_pZ-^xncpRoMY zPXzLksUbMz5kkNl-^@e5-Uw49kQa-seIQ|o5d-%zgi6G?(h4CGtLnB+0ZUo%FD)rL zi?ijW!|yF^+0D8eIDaXKW?$Xek*>hiGQ^`$wy_ru9Co0W>Dk-+q*){2wjrBlHpUtj z8Xc)f@~W2hZN*NgDL=`pX zD-Y=y>&R(cCa2JX8mVAGAQu0~P~Ddcr^F%nxxDD|dEc4uC@eHb<>PeM?D1-`Rz+)O zW^C`JFJly(YwWFN5udEK|EEoBO;rnaeMs_}i}BIy{45zqw|>=>@oB{41{%)pigQRi z%lE13LAAF~USsMx8JZI#pYEC20wv)%H#@k!215d{UPqVJ$$yKYkG4-vmYC3X+Eo6Y zuoTW02L85Ap`@f_cvSp-PN6Pc{Urzz9=ETbKVR+tc}_^U{@qsMpy;rUERe0Fa5HaJ zT5LiJMi(sAotEYrY%`c30f<%rf9gV6RDrDi80Cm+v80PmArKAC%|4y^ySG;yo@mVO z!r2*Fq70xe+$C30;+^kXc3~YM(|m6BQDb6)+jhY(^luH;7~+26TRzUT(@yYMAW!>b zZ&uH@^_5tRVVWc8QvdG&B7D1t5`^ zTk|h(T6RmA32y6N2ZsNti~j$t472EssqNMmKddjBo0#+hlLQ`@Er2R|o|<~zY?GhX zOi{kQox#FVhUrq1fXRPbo9^vWS5>;9_o`R;C#F2ujomM*#RO$~!mCYbZ)@38P)??@>DU4cs?Qxbtp8r$;d9CeE&-I>|47hNl$!rlA&AFcWB z&ip`~3=2_9Q%f=d@s^vwfAlQ*Mr=@CPEJm1X(Z7DzqXo)h#0VAMC*}(H@_>is)_x}SOPO-@R*sNo`%EsPcPTj@|)p$^`m`#eLsK3_N;UB@T7Y5tfMI?DCmfY z#>G)Wl)G{3j8CWe`AG839qAMGc)7VIC#EtGs()*OWIbK(hT8F|$+2=)7FN{uwlyKn z^vK8v91dSP{BRFYHvrw&Cb771i3PRo{MLlhWcpCS=lje{-!V)~~3-3yus<)Y9?tQc#G{q0SGb z&Sv1HZ)hz1=0QwB#{5j-!<4o`xX^}CLnRns;HE}a40!`Rhrl` z2MceeB)CZysowSooFst1fnR{Xnvmv`*y6^ewUXAF0N3&*8cv!Axlej@ZMKhD`H~3y}iS% zZ?0U($E+6^r!C%Is*RYqxTD2&a-lIBwR#vbp~H}!xNs^d$BOeRZR8#>h|&S z{x=Tt!0S|%dX>8PT~}An2_B}Ril78x@y7S>G@*DUnoR8MyT`DS($c(E&vQ*1CHE*X z267I&!q2%H-qwt_A;U`>-AOp%^hNxxS)+Nh%FJgbDNU?6`1Ipo@jB_1Rg_W*7bz=v z*we|0%YJoxxm1%8ML~|Dz{Vq#53VTz1g)W^Uy_uaH4UDXNxHM}nPP4mJ$>V;#r0j{ z7Zir>I|km~QUOLH!E_ihJ@8agPft$|u?*$)?KQZF0U;qFM|Yf_y?s=244(am-S@`d zjDKjS|8e2B;D^1;P^ow+3O>dcc>mH~9i;Dj`r{pigYVN~ODx5$S6ts;LPLXZeYC3al zD|qkUe~(bhi8e(MQk6W7;oul+OeMerCV&I1WiuZ1nZw;^s{T%Vy&zRDi*OAKM3{^I8;J6~1R#E+)W&SB?vBGsaz1ySZ>R(;E$HsECpF-zQp!K)QH1QerCD6Tgy^Q_$q(d`b9m8qyDBmuy*D z7iT&L@wQi(%`GjV!J!He_03$EZIKj2Jt;A9Y;9<0i0dBfgU~M@xD1;;sqAItBD)E~ z=rWCrqLqi}=%hjjyO$H8P^b>ej+2jgc4eT`Q;1-;>aX?v53d`o1^=$#kEl{SW{@OA zb6Sw^;Or7cuhB_OW4f|j7#pN5t=GIX)`A5>OiYfinOk8TZpnyh$`>;f$g97wpHMYc zc^ei`n5wC#zKk+!{A_F~Z7JzyZr~@>Vy|ZM3g>%r8ad43n%-v3yG4X>kN>W#1dWN~dI^NbvmYtsrht zKy4Oko}aPp6R1LU(^h6sXL1<{vzSunvUzSuQlqc>G;t>Ji;X*mbI5^;O2r_|GqaS9 zS2)}Q)34!Hneg4_{`7CR-kBo(@9g%!=)eE1*M3}a>RQ>S^jpks zZ2Xzw*>bklizjmUO^4R<93MPf098!!Nh`8g8xSn)y0jXaYs#;a2*p*9CFwm33T?UY zKN-vqM#8KfJbJ{DeteJ#s5q{{CnmkJ@@H!Qj8&>rDcVTZlj{h3F&c>fV zznli?82W_Wo4_;=Z9=aNrn<*`&b<#ymZW}$viKSFFh42w z2~AHFnW)L-0~@f=8Ic~Pphvnj${v0{TEbTS)C$y!k2r0^c~zi zJ<~X?a4pP2Y=7n!1kbxr#q?0QO;LwM*fx3bXc}* z?{}z?|KK6+Uw-v5kSf}-OT=uALRVM!-Me=Q3}a);X>iD-IxjJ=ykKT#CeI{~9SyjL zjKl4#dXXZ3Y)8E+E3>7lqP@NUeF~{uHhvWl)|Z!EdUFssHmVKA<|FmJNhpz z;P~9OVoWcUaP_ z=KK(!^D{u-u8Xi#&K*@)SzP><>QkNlvy#}+5iA;TQI=ihympA(=ETPgR#O}0T5oO^ z@JQd=d(2#9aj(woV7r+bsU2tqx7fZ29q%y)b{T zw7IUUHBHR!RV=)gXZ(#oM$zcZ3_q8fn7twE#REeF!>vsl;d$XXp}F|@_z9*u>wD$p z4n5Hn_BFQ0jqcUi$fF$jtf(j@GYPZpEFh_O(b07!`*sb!Sg>1I0Gess+`Lt+nwbat zXeHs4zP1fTncZ*9xLALqc#49pGcheKEjf8=xhq1uT!%mKI*3joldDXx?GjS?SmLhL zPU~4)K!Du}+d@eG8Y+<9umo)S*f3@2-yFbH z6p~qe(e1V#+jIL@C!&c-1frLF68YCaSJ|lEu1UFsFsw^XPEG+F7@adJL*>uHH6#xa zXqPD_uwS?g^hDSfeilBNLk|tH`JQZ_xuL9*l86XOY6a$D3YkFT4qSF2Bq|D4ze~Zz z!_VS2Yxfe;qS@e~!h*=C|pE-=?bS1#JY`6z+ znykP|!rpO4K@y>O(8Do#PtTJkSIgma@18(P{{+)J6cYf{l^N`horqq_rl|^LmF=|b zE&vMQacFG5{Bv!FKLoD>&sLN1M7`RTFxphP(5S(7Ax{6_=~gJ{JyvrMpN!0&^{eaU z?X^wx%mlpmYEp~LCSqvE3+;Rrj6=*CVAmb_;!u6;3lP#quTBp>bg?ySBIImpmqIrp0v z5LiPQJHxcOhLVl_SCPmr%5u+z0Nbs}vaPAWrS;tk&7xn_qs_yU0VngG6m1d$FNpqb zvT_XrBO<=QpW^ia)&4!lg&PdTRo}Hoz1L?HB`lDkRBbmKop>|do14WrWIS)WW3E)K zFkksV1CBO9xD@hvHe+aogMvq2yPWaF8 zWFvw2%!Nej*_j#CY{SW<{!k!K*lY0j@29`wRiGC;7x(Vo$kjB8CyBHlR+I%Qr}Hh1 z-U#7SQBjdSZ?QXzP#PS3P9Ir7Rs1o zq-O8i1CU57pdUbGSo_t8CY2vW$L8Qu7Z9ZksV~6;}v3X#@ zKEh{hZLN{7Y$D*(rIbNDV7#%k#BX(MCt$$HNWVU4>~zzCQRpZ03TzZ>KYQ)7_%pQd zDSSyVFW%&DI$9LyvS^f-C3)A52w0ylEd0Rari$~cHoT7lCn_Xj1Sm2~N=jzBPY{78 z{p^z(IG;GA-Q2Jzq95G*x!e^KOeUJg^vGp=rc&>$S~Mvzz%IR$X3NBdGj8L9!@LYHjSJ@ zhS9~DbcO_;T%E9&>AYh#>xpqa*_&=YQi&Rk5xsP3f}VQ$I?f+h*(xx*=hm()Zv3uq zZ?#E8ZVJYw`otA;H7sxh2jLJ#&&>h2cne{VeViReruTLV% z$<39Qm;bP|F-luJe!iI__;J)W#&1UDz$HhDgdkZf4aKB zd9iY6ZF9Dk=4h-7^;x>Yx<0*XIDTFz1&mh-S zNVs?vgnO26r?(*(zyEoAxjpP`DU>onM^8P>ao(X)Dshpc{AjGfol#6;UNUxx*`N670Q{emDZKEBgPxbaUBz2(q%Wma$L zZAEOy?eE`@cfSpV{xt!7+#;|_ei%(E4DaYTkUV%IoLeC9M2p{{-T&MZ5ir~PdetJN z#-vWK>y5TR*%BuYQ(~Nr>Nflw?qf^VDfL;N(Ea^J`t-=VqBr*Cu+3RV>LijK8G0hJ zfEwbbMzP|f@ciJQZ<Ym2wx#Nkr64RR{kM>+ALds`9-Q;1TtEolpfzRH! zEjQ95;H`(t!cv8NO(rY(V`F2Y4R+ZLKQ&Z@yXyN1UC{P*dQlr48T3*a3qjR`At>v* zW`%tCD6@l}ZKkEapI=Un*`W^wIPluAXMKOBY5(w?=l{M7i6y?f(3pEa;^cmO2@^Qnl5>LYT;m78cTY z?1g*|H@5j*zubGL?68x-*f0a1Q727t9~MUSG;l9avkTI%PwE#4@bjxRc%#?Af*@y; z-E*F+z^m1%tgM%vuV-eYq=HxI6=elnezks9E`i7y?Mok1Qc^O~E32xIrLb_)2)}vr zO?e;G+9-6Sxf%I_6X$MYQ&{wL*q=W@6pu+17gGpT4o^)Dcf&)BTBrgqgI(sq`VAuI zV41+{vx1Wa->I>&xG~%^|ML{9i<4bPxY~A>4%34&gQn%hPxli_%XOMIRUMWm4R=M% zR<;QPwz|@g-oD-%dtMi)hJdqGD<4+227A-x?2jKm?m0;m>eu_d=*++cvLpP@pA|Pv z#?&#}^G(|dm2|$h`|oqw+XLMcxylTiYzTuH=I>DvYkG<;yZfT-Wl_9NCze z1CJ&qwwW@NrpX-?_D5~1;ui#Z(8~;$Jt*uS)u4wxE_wOW>&ezR9 zSpyyTL26ZJ0Q{fs7o?_c0xS~MfCy;u?~bGp^kfCr`ebL`CJ{c5EceKeUaUM z!!bvEz1!}2dE7&#Xvwwfh4poV$U0ccE;rUcK5jYT@`4QNo5OxB>$1=&adY)63vu#_DiP zF+c%!Z(FUKz@^ZgtzJi>RYjF(Z;{S?<)bbG`^0{Nr*#Nl7nwe`$#{FgOgd@@A5 zq-9~^K6?zK31JG4Ds5^)x-R7PwBxOMRfg8UtiwT)6$(eQgoO4>lMX0;tFKC zX841-YTE8!y_r; zQaq}+u7v$BD{LBr0`FQ`tv|#fD%V9zg9Ln~5L}k~r1@#rI&T}w`Tlh`?wqb4zBF*Y zr0dwLkbz{gy=GRAb8+enTKcCh{lNLyuU~bmjm%a4zno?Ntt>1SFR(f-=gGCTwdIE@ zDJg|Mf4&lmeYF(2o8oYQK8c|s5A4D@^Si#n6RLFX3;}3Hm`9~bW}W+uaY*r8jqGjqN^`GV65 zK0WP5Qcfg#eERWjc8t*Fo7-uRXn=tBO?CAUo6%t*GFy^bPM*V$t_mnA-QDW|p-qU`cIl6+)pX3=9ls-u=BJckcKsQeERO^~TeS9{vsl zNc_!Fh|FZmPTfDw};AiptelXbpL`% zzg8eal10R0d!uGpsAjF*R!^T$A=4*lvh8Bw!omVlqFriN)6)a?TCShXFVbR))wu*p zvE!{Nb~cAMF+CTT=p&7SxxU*89m+a(P86!;0;-HGmT^E;0Fb6Z+ba9W3j5jVRrf8C zsVyc@wbp-W0k!#BSLY9f4)!Fv=(_al?fh4wrfwGM?U7@|A=nf=R>#{^f#+u%qq&aI zGh=i%!!!TApBU{o_1>p@OC`qs_8TK6pgG_7?_biDtY`WsbxdELVO^uaGW1HRVy{?f z`Ti{UTK%URB0MqcB-I;Uthg->>d^Am1?p7)UN*3@Ah-E%Rah}1;DVKtGoA=wYMFrn zjKN^Q=D|Bv+BB!il$aVv$V&VAH4hIDEiLUE5C^ph?NxwHuSVpnw0${qNrL}u1zXTX z^$&P693@!q*;t&{_{H$MsH20qdD=F;gqsRrnG94D{_Au>| zQJcCzhqHKp2Ki9(}-W$+1Wcg4k*tm&tb}J)#>T+ zT5Fgz)JW8JvNYt}2VS8=ZFzg&e6kx7OQ6z*sIsXB+Yhtq-@ss?;JwD6`oKl{No=oY zw_VLl+ULA*G*=kf3J7}vu#kjC%Yjz2$x>f0p@kj8mS{>PKqB33J6Whl&05d$oDiCO zD!tlEbL0^=$1)We}jIx1fVC z)fJ;N1KQf?AdrOo=}l{%KGHLt*rkIIRDETjz;*B&F_&{ z6{P`3Wep3Nf{vN0(+#{qV4vCAkr7px1bqH8o-i#@SViN~A(Hd_WOsLc%Xezt^FPN= z44t$(Cvv1Bj063n0367Ths`yidHm6=u;jJDG+u{oK9~eEGqP0oWEwtWk<0$jXs|8p-Y?ry!pR1sYH4wv54anBui|n`?jmBz$`lC*aA4@k#9I zix*PCj2aQ41y-T`YadKamX_|`y<5wIAK`a(#md4`$O(?wV){3SA6bs<1GW++qpFop zaBv2H|DLY4=x=gOd>H&NK_7tBOqU3~vTTtEVs^kHes)k&AtVgtB8^gI$Rm-?0Q=bV zCKPFC$wPDi;FR~dZn8q?)O5o-HEit5U`U2P05Wvy>RN$Hb@*)#KS1Q^@G*;^SLAK* z%GjPgNoo_I7cA?<&D%UGw zWA*tWNR!2N&_jUia^@pMoI4s@Tgl~Ru-4cQ_x92`eUHEFuc)gl52dxgWMKFnHxWt| z@Wy%h%WA*T*O-`s2U7RLSy}Q`z|!*sm|c-6oJF|OsEYRUO~7^mDl?c_vT9Za%R?yU z-Pb92c&dA-0^^WDi6urwB_%0<2dcJ6gO#<+)NDn&)GI7*7Vw?Lmi`N!j}xfFY9%F;@G5Umx({kW+e}z#-R{;WWezbRMjOf`H0UiDR(oz<)M_qq! zcmjb&e_TQ4dkj#~c>CogCoBEy*OLqA4cwrYy&d$g@{6CKx*|1i~6r$A2S(EOirq; z%F2)E)fwfOs5A2R1|p|?zS@GhE+ILw{pQ*iaCLHBBLqDLGC0$M=x(zguh9QMablsl zdBeH60~a(Y8JS{~=EJy|zT%P+C00O=2S}#oE(c<=zrUrlw6=5hPO7St%gG)CGb_{p zgO|4%PS25Zq{IXOFnAU204BA9YCrPLlE%v6;2}Y-d9x61lXtvN~F0uS*l! z)9^%%2*0=TR7X(%1-Qo+fj|t;&JQLMbznTuSAbx9Dst|lk33va(jnP2Z(in!vhwi@ z9O4~XokyBn20%$g1x&M4Px1V!xc|;TZ1?K^QZcwarlrKyRQ;gpc~Jpuct_N2{O3@T z`qMHFEmj8G(P~C#UG=PI5i=H_#KgMTpvqPPSOvdd5gDuRWN8uPocd*Elqnhd=K`2r zuPMf9L93@wN9>_Xo5LpVE2vLuPykDbSzJX%wNa;1_S@VaJi}~zyuUotuj+_@%lKa2|ImSqrTAAYI8q@e@q*raW z?y>(WMrJtqEu~+57hF%iCAUBVZI{>|)$`6g)4HhLnfb03>K~wdv>lr$#~(R!{scF5c**PNcI;~kyoV&q`qV&)ai3lxRhcwJ^0Uf_FoWAnV^`{wd8>M8y> zJAHfQ;2Z;7wXV3WZB*Mbcl5(X(I`4RoJ7nu+e=kXJ2rsF>Vtt>fQhr5?!&0XEmV{J zx=6QbBB=|H;Ba4G2VzRUY*h7{KQ&$cU2q1EFhwe!VEp_Ap4wyN`Ysthf$WpKtU_8& z=BZhjFc+U{nYIRg&bUku>@dOFlfa$f`1dL%W`KC?hw-nk#@Rp&c$6a2@s6%{tS6>p zJJa;_fNri*Ze?QvE*2e+Jg+a_Yqd>#1ma6~L!4fei*wG3#PIUs(#j#zgGZ+iADuF3 zF_FHaVNS*se=jOp?5w6}lgP|5wDwCnc=SUpyN?1F4>yc&>AnO*0POK$WSmO==)ekw z6pRBRpNdDp@UQk;guB*tCPqaibSUa}@uQ^$qLRK!d3bPyGuSzYD8qm$G1jX36qS{U zy1$O^=-qqe%%-f2OqnSkicU};($emc4B>95SAQ1C^WrU6v~n9G@yxW&?p&JeOvt^k zmNW%3vv_NneEX7OTWNaiT-f3Am`ibOB)JG5dwXGCsSv{mxZ`7c#ngTRtj_(2N1d_j z{^oFt>U@rRT21^4@=y`;O@canAgY+n4i&ttDq+S+m~5KcsRFS`(9%>VWH32h+-|)G zG;(~oG=D^P31AYku_^mN%WGRrFE`TEVH_LYYLDG28#seY4#MT>F?>B<+l_{C5Dunu zB!Xi=Rki7H6HB@Dg_&z>%X7oSJwgU_6r%i=e=6rMa7W+en^^DNw|+sOD}x(T!2bp3 zv4iWKy6zQY9ZmTanP9vubEy|{*_z5EoE?2*K|#)G*P8ieo|5cD6lcYo@B|I34JSHm zGR0Z-R_r~rh|?*_Lx6X3-Ngje65_a@>V&HokqetLKz@!LxNavfc&ML4Z}1&+Pyg3RqMFE`W(w@^Y}QV z#-sQ~_SZ6J%8XleISk2Yr+TNPxF|aZGqI_VX?1y9wl4bJ+h?^;=w8sv_zG|r7)Z8c zB^9UYg;NXE_^V->Hb6GSi@GN!QUW4T_w-j*{iM1qG%e+XGv4)v!%^FIu4v4G0w(+? zMMj!drAl?+v|r)_lSb3yOURwckrCP6a6JaFYHRk0tUC$mCmZbvZg*T<5AoPHBZy>q zf$`7-MYmsK@}&F;KmTB&uTm{d>1(o|N(o2BKU330@4FSOydXDcsD2Wq@`W;W?B!s1 zu{3E}(!rB1cx@z0_jjOEhIDT}#`w1Uw2Q>U4^yb=p%jJjz{^03IuP}s0;HZGp5|hbIo$?uxo~q6O ziOOIGIr-SIr2<6Tt=#eacl>9ly+c53Mj5LGVEMDRzx;)(l|EfZr^rti6>!~#6Sa;d z;Ye&dMe z8Ddqaqy~)zQ@E)c>AbF8Ye6wAMIZJex#RM-vaZ=W>2P-M$wmWdbi0T z635T)&c290&Zy%hV}2zM8Qar`6c?7}v=Tid>ZosNX&UQ=0!$$^&DMYRgIj=pakr{w z7J+klF}$m56fvCUp~T6^#0KHKc)7y5JB_sm*ZhWkV)w=}F?#(q=iKP0Vtq~0oK!;n z&1?#_B|2)MgrKKUlT090;m{lkVGGQpyVoMf?gP;2kM~Sds?&V-EZ3@G!?hadlo3iL zm2jx{qdE++&gsM`jA}{_*m#S|fz%~>{4~SnMZZT=x_h`f-xe0-a-bF$DXWQ|IE`GIN6I8= zV*Q%3*_@67v-w((Rl-=4Y?JJFQQh~jR;kXj&+#lMyGdB1$raw#lid^Zv(r>R=p87X zJAJ1Xq8@JqPEC4eJ8W(~`uMQZC|ujudbQ6_KitSn8rMulBsHCs`1$DgcwC15%cpzy z@B3v?P)y@}R3hOt1@e9VGlrx}t=IAt_G{9vS#Iw}BRqZ@g~?Db7(`LNP3X>ca-rsq zYWf!YLFO>6gD@CcY$HKeTv?cqiG_*|(ss8u%$OM{viUV+zP=#Ysq{E%2{8X^e6;?M z7ndd^!s7w}JOkEfNE0!W0*gTXpea`tndUzNg4d(KbW#JSY;^T$qHP)uDN%yAUI7aTrn>my# zo5|o7SolCmBQJy#llU0~<`7e9-PzY}rZnUgjL8}g{q_B+JGU<1c}efg%8*s_&MukUP<}M#`r4GMmH+wpJ)VEudiZuoNs$bs zsqXv#z;q5sFX+#2cyFTN`J;!2!3uzF=>zRscIL~^bU}2Pgg&ebxsLQ0CXwQLjV8( literal 0 HcmV?d00001 diff --git a/img/trix-light.png b/img/trix-light.png new file mode 100644 index 0000000000000000000000000000000000000000..5c22dc513eaa168b946b16ab10918baf5859b78c GIT binary patch literal 17866 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 J75L)wzW~m7P?P`w literal 0 HcmV?d00001 diff --git a/test/dummy/app/admin/editor.rb b/test/dummy/app/admin/editor.rb new file mode 100644 index 0000000..13f9b73 --- /dev/null +++ b/test/dummy/app/admin/editor.rb @@ -0,0 +1,24 @@ +# Demo page with a real Trix (ActionText) editor so the theme's Trix chrome can +# be seen and screenshotted. The hidden input carries sample formatted HTML that +# Trix loads on init, exercising the toolbar states and .trix-content styles. +ActiveAdmin.register_page "Rich text" do + menu priority: 2 + + SAMPLE_HTML = <<~HTML +

Release notes

+
+
  • First bullet
  • Second bullet
+
Quoted text follows the theme border.
+
$ bundle exec rake
+ HTML + + content do + panel "Trix / ActionText" do + value = ERB::Util.html_escape(SAMPLE_HTML) + html = %() + + %() + text_node(html.html_safe) + end + end +end diff --git a/test/dummy/app/assets/javascripts/active_admin.js b/test/dummy/app/assets/javascripts/active_admin.js index 6780be4..eeb250c 100644 --- a/test/dummy/app/assets/javascripts/active_admin.js +++ b/test/dummy/app/assets/javascripts/active_admin.js @@ -1,3 +1,4 @@ //= require active_admin/base +//= require trix //= require wigu/server_clock //= require wigu/theme_toggle diff --git a/test/dummy/app/assets/stylesheets/active_admin.scss b/test/dummy/app/assets/stylesheets/active_admin.scss index c0252fb..6ccb9ca 100644 --- a/test/dummy/app/assets/stylesheets/active_admin.scss +++ b/test/dummy/app/assets/stylesheets/active_admin.scss @@ -1,3 +1,4 @@ @import "active_admin/mixins"; @import "active_admin/base"; +@import "trix"; @import "wigu/active_admin_theme"; diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 513502b..7537079 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -28,6 +28,14 @@ class Application < Rails::Application config.logger = Logger.new($stdout) config.log_level = :warn + # action_text-trix ships trix.js / trix.css but doesn't add them to the + # Sprockets load path on its own, so `//= require trix` / `@import "trix"` + # (in active_admin.js / active_admin.scss) can't find them. Add its asset + # dirs so the demo editor page gets Trix's base JS + CSS. + trix_root = Gem::Specification.find_by_name("action_text-trix").gem_dir + config.assets.paths << File.join(trix_root, "app/assets/javascripts") + config.assets.paths << File.join(trix_root, "app/assets/stylesheets") + # Sprockets: compile on the fly, no digests — simplest thing that serves # active_admin.css / active_admin.js in dev/test. config.assets.compile = true diff --git a/test/trix_screenshot.rb b/test/trix_screenshot.rb new file mode 100644 index 0000000..5e4f7d6 --- /dev/null +++ b/test/trix_screenshot.rb @@ -0,0 +1,32 @@ +# Regenerates img/trix-light.png / img/trix-dark.png — the themed Trix editor +# (toolbar + sample content) in both palettes, for the PR/README. Same dummy app +# and driver the clock screenshot uses; crops to the editor panel. +require_relative "capybara_boot" +require "capybara/dsl" + +include Capybara::DSL + +def shoot(theme, out) + visit "/admin/rich_text" + # Trix enhances into a full toolbar on load; wait for it. + find("trix-toolbar .trix-button--icon-bold", wait: 5) + # Place the cursor in the content so Trix enables the block-format buttons + # (quote/code/lists/nesting), which it disables while the editor is unfocused — + # the screenshot then shows the toolbar in its normal in-use state. + page.execute_script(<<~JS) + var ed = document.querySelector('trix-editor'); + ed.focus(); + if (ed.editor) ed.editor.setSelectedRange([5, 5]); + JS + page.execute_script(%(document.documentElement.setAttribute('data-theme', '#{theme}'))) + sleep 0.4 + page.driver.save_screenshot(out, selector: ".panel") + puts "wrote #{out} (#{File.size(out)} bytes)" +end + +page.driver.resize_window_to(page.driver.window_handles.first, 980, 720) rescue nil + +shoot("light", File.expand_path("../img/trix-light.png", __dir__)) +shoot("dark", File.expand_path("../img/trix-dark.png", __dir__)) + +Capybara.reset_sessions!