1- import { createEffect , createSignal } from 'solid-js'
1+ import { createEffect , createMemo , createSignal , For } from 'solid-js'
22import { useStyles } from '../../styles/use-styles'
33import { useHeadChanges } from '../../hooks/use-head-changes'
44import { Section , SectionDescription } from '@tanstack/devtools-ui'
@@ -37,8 +37,7 @@ function getSerpFromHead(): SerpData {
3737 const descriptionMeta = metaTags . find (
3838 ( m ) => m . getAttribute ( 'name' ) ?. toLowerCase ( ) === 'description' ,
3939 )
40- const description =
41- descriptionMeta ?. getAttribute ( 'content' ) ?. trim ( ) || ''
40+ const description = descriptionMeta ?. getAttribute ( 'content' ) ?. trim ( ) || ''
4241
4342 const siteNameMeta = metaTags . find (
4443 ( m ) => m . getAttribute ( 'property' ) === 'og:site_name' ,
@@ -50,9 +49,8 @@ function getSerpFromHead(): SerpData {
5049 : '' )
5150
5251 const linkTags = Array . from ( document . head . querySelectorAll ( 'link' ) )
53- const iconLink = linkTags . find (
54- ( l ) =>
55- l . getAttribute ( 'rel' ) ?. toLowerCase ( ) . split ( / \s + / ) . includes ( 'icon' ) ,
52+ const iconLink = linkTags . find ( ( l ) =>
53+ l . getAttribute ( 'rel' ) ?. toLowerCase ( ) . split ( / \s + / ) . includes ( 'icon' ) ,
5654 )
5755 let favicon : string | null = iconLink ?. getAttribute ( 'href' ) || null
5856 if ( favicon && typeof window !== 'undefined' ) {
@@ -66,6 +64,32 @@ function getSerpFromHead(): SerpData {
6664 return { title, description, siteName, favicon, url }
6765}
6866
67+ type SerpOverflow = {
68+ titleOverflow : boolean
69+ descriptionOverflow : boolean
70+ }
71+
72+ function getSerpReports ( data : SerpData , overflow : SerpOverflow ) : string [ ] {
73+ const issues : string [ ] = [ ]
74+ if ( ! data . title ?. trim ( ) ) {
75+ issues . push ( 'No title tag set on the page.' )
76+ }
77+ if ( ! data . description ?. trim ( ) ) {
78+ issues . push ( 'No meta description set on the page.' )
79+ }
80+ if ( overflow . titleOverflow ) {
81+ issues . push (
82+ 'The title is wider than 600px and it may not be displayed in full length.' ,
83+ )
84+ }
85+ if ( overflow . descriptionOverflow ) {
86+ issues . push (
87+ 'The meta description may get trimmed at ~960 pixels on desktop and at ~680px on mobile. Keep it below ~158 characters.' ,
88+ )
89+ }
90+ return issues
91+ }
92+
6993export function SerpPreviewSection ( ) {
7094 const [ serp , setSerp ] = createSignal < SerpData > ( getSerpFromHead ( ) )
7195 const [ titleOverflow , setTitleOverflow ] = createSignal ( false )
@@ -110,6 +134,13 @@ export function SerpPreviewSection() {
110134 setDescriptionOverflow ( truncatedDesc !== descText )
111135 } )
112136
137+ const reports = createMemo ( ( ) =>
138+ getSerpReports ( serp ( ) , {
139+ titleOverflow : titleOverflow ( ) ,
140+ descriptionOverflow : descriptionOverflow ( ) ,
141+ } ) ,
142+ )
143+
113144 const data = serp ( )
114145
115146 return (
@@ -151,22 +182,16 @@ export function SerpPreviewSection() {
151182 aria-hidden = "true"
152183 />
153184 </ div >
154- { ( titleOverflow ( ) || descriptionOverflow ( ) ) && (
155- < div class = { styles ( ) . serpReportSection } >
156- { titleOverflow ( ) && (
157- < div class = { styles ( ) . serpReportItem } >
158- The title is wider than 600px and it may not be displayed in full
159- length.
160- </ div >
161- ) }
162- { descriptionOverflow ( ) && (
163- < div class = { styles ( ) . serpReportItem } >
164- The meta description may get trimmed at ~960 pixels on desktop
165- and at ~680px on mobile. Keep it below ~158 characters.
166- </ div >
167- ) }
185+ { reports ( ) . length > 0 ? (
186+ < div class = { styles ( ) . seoMissingTagsSection } >
187+ < strong > SERP preview issues:</ strong >
188+ < ul class = { styles ( ) . serpErrorList } >
189+ < For each = { reports ( ) } >
190+ { ( issue ) => < li class = { styles ( ) . serpReportItem } > { issue } </ li > }
191+ </ For >
192+ </ ul >
168193 </ div >
169- ) }
194+ ) : null }
170195 </ Section >
171196 )
172197}
0 commit comments