@@ -121,6 +121,7 @@ <h2>Beehiiv output</h2>
121121 const BLOCK_STYLE = 'font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);' ;
122122 const HEADING_STYLE = BLOCK_STYLE . replace ( 'font-weight: 400; ' , '' ) ;
123123 const BLOCKQUOTE_STYLE = 'font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);' ;
124+ const TABLE_STYLE = `${ BLOCKQUOTE_STYLE } min-width: 75px;` ;
124125
125126 const updateStatus = ( message ) => {
126127 status . textContent = message ;
@@ -148,6 +149,75 @@ <h2>Beehiiv output</h2>
148149 return ! hasMedia && text === '' ;
149150 } ;
150151
152+ const applyInlineFormatting = ( element ) => {
153+ element . querySelectorAll ( 'a' ) . forEach ( anchor => {
154+ anchor . setAttribute ( 'target' , '_blank' ) ;
155+ anchor . setAttribute ( 'rel' , 'noopener noreferrer nofollow' ) ;
156+ anchor . setAttribute ( 'class' , 'link' ) ;
157+ } ) ;
158+
159+ element . querySelectorAll ( 'code' ) . forEach ( code => {
160+ normalizeCodeLanguage ( code ) ;
161+ } ) ;
162+ } ;
163+
164+ const convertTable = ( tableNode ) => {
165+ const rows = Array . from ( tableNode . querySelectorAll ( 'tr' ) ) ;
166+ if ( ! rows . length ) {
167+ return '' ;
168+ }
169+
170+ const columnCount = rows . reduce ( ( maxColumns , row ) => {
171+ const columnTotal = Array . from ( row . children ) . reduce ( ( sum , cell ) => {
172+ const span = Number . parseInt ( cell . getAttribute ( 'colspan' ) || '1' , 10 ) ;
173+ return sum + ( Number . isFinite ( span ) && span > 0 ? span : 1 ) ;
174+ } , 0 ) ;
175+ return Math . max ( maxColumns , columnTotal ) ;
176+ } , 0 ) ;
177+
178+ const table = document . createElement ( 'table' ) ;
179+ table . setAttribute ( 'class' , 'table-fixed' ) ;
180+ table . setAttribute ( 'data-id' , crypto . randomUUID ( ) ) ;
181+ table . setAttribute ( 'style' , TABLE_STYLE ) ;
182+
183+ const colgroup = document . createElement ( 'colgroup' ) ;
184+ const safeColumnCount = Math . max ( columnCount , 1 ) ;
185+ for ( let i = 0 ; i < safeColumnCount ; i += 1 ) {
186+ const col = document . createElement ( 'col' ) ;
187+ col . setAttribute ( 'style' , 'min-width: 25px;' ) ;
188+ colgroup . appendChild ( col ) ;
189+ }
190+ table . appendChild ( colgroup ) ;
191+
192+ const tbody = document . createElement ( 'tbody' ) ;
193+
194+ rows . forEach ( ( sourceRow ) => {
195+ const row = document . createElement ( 'tr' ) ;
196+
197+ Array . from ( sourceRow . children ) . forEach ( ( sourceCell ) => {
198+ const targetTag = sourceCell . tagName === 'TH' ? 'th' : 'td' ;
199+ const targetCell = document . createElement ( targetTag ) ;
200+ const colspan = sourceCell . getAttribute ( 'colspan' ) || '1' ;
201+ const rowspan = sourceCell . getAttribute ( 'rowspan' ) || '1' ;
202+ targetCell . setAttribute ( 'colspan' , colspan ) ;
203+ targetCell . setAttribute ( 'rowspan' , rowspan ) ;
204+
205+ const paragraph = document . createElement ( 'p' ) ;
206+ paragraph . setAttribute ( 'data-id' , crypto . randomUUID ( ) ) ;
207+ paragraph . innerHTML = sourceCell . innerHTML ;
208+ applyInlineFormatting ( paragraph ) ;
209+
210+ targetCell . appendChild ( paragraph ) ;
211+ row . appendChild ( targetCell ) ;
212+ } ) ;
213+
214+ tbody . appendChild ( row ) ;
215+ } ) ;
216+
217+ table . appendChild ( tbody ) ;
218+ return table . outerHTML ;
219+ } ;
220+
151221 const convertMarkdownToBeehiiv = ( markdown ) => {
152222 if ( ! markdown . trim ( ) ) {
153223 return '' ;
@@ -188,16 +258,7 @@ <h2>Beehiiv output</h2>
188258 }
189259 paragraph . setAttribute ( 'style' , BLOCK_STYLE ) ;
190260 paragraph . innerHTML = node . innerHTML ;
191-
192- paragraph . querySelectorAll ( 'a' ) . forEach ( anchor => {
193- anchor . setAttribute ( 'target' , '_blank' ) ;
194- anchor . setAttribute ( 'rel' , 'noopener noreferrer nofollow' ) ;
195- anchor . setAttribute ( 'class' , 'link' ) ;
196- } ) ;
197-
198- paragraph . querySelectorAll ( 'code' ) . forEach ( code => {
199- normalizeCodeLanguage ( code ) ;
200- } ) ;
261+ applyInlineFormatting ( paragraph ) ;
201262
202263 blocks . push ( paragraph . outerHTML ) ;
203264 return ;
@@ -247,16 +308,7 @@ <h2>Beehiiv output</h2>
247308 const paragraph = document . createElement ( 'p' ) ;
248309 paragraph . setAttribute ( 'data-id' , crypto . randomUUID ( ) ) ;
249310 paragraph . innerHTML = sourceParagraph . innerHTML ;
250-
251- paragraph . querySelectorAll ( 'a' ) . forEach ( anchor => {
252- anchor . setAttribute ( 'target' , '_blank' ) ;
253- anchor . setAttribute ( 'rel' , 'noopener noreferrer nofollow' ) ;
254- anchor . setAttribute ( 'class' , 'link' ) ;
255- } ) ;
256-
257- paragraph . querySelectorAll ( 'code' ) . forEach ( code => {
258- normalizeCodeLanguage ( code ) ;
259- } ) ;
311+ applyInlineFormatting ( paragraph ) ;
260312
261313 quote . appendChild ( paragraph ) ;
262314 } ) ;
@@ -266,6 +318,14 @@ <h2>Beehiiv output</h2>
266318 return ;
267319 }
268320
321+ if ( node . tagName === 'TABLE' ) {
322+ const tableHtml = convertTable ( node ) ;
323+ if ( tableHtml ) {
324+ blocks . push ( tableHtml ) ;
325+ }
326+ return ;
327+ }
328+
269329 if ( node . tagName . startsWith ( 'H' ) ) {
270330 const level = Number . parseInt ( node . tagName . replace ( 'H' , '' ) , 10 ) ;
271331 const heading = document . createElement ( node . tagName . toLowerCase ( ) ) ;
0 commit comments