Skip to content

Commit f053469

Browse files
committed
feat(devtools): add SERP overflow reporting and improve styles
This commit enhances the SERP preview section by introducing a new overflow reporting mechanism for the title and description. It adds a list of issues when the title or description exceeds specified limits, improving user feedback. Additionally, new styles are implemented for better visual presentation of error messages in the SERP preview.
1 parent f9046d1 commit f053469

File tree

2 files changed

+54
-23
lines changed

2 files changed

+54
-23
lines changed

packages/devtools/src/styles/use-styles.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,15 @@ const stylesFactory = (theme: DevtoolsStore['settings']['theme']) => {
296296
font-size: 0.875rem;
297297
color: ${t(colors.gray[700], colors.gray[300])};
298298
`,
299+
serpErrorList: css`
300+
margin: 4px 0 0 0;
301+
padding-left: 1.25rem;
302+
list-style-type: disc;
303+
`,
299304
serpReportItem: css`
300-
margin-top: 0.5rem;
301-
color: ${t(colors.yellow[700], colors.yellow[400])};
305+
margin-top: 0.25rem;
306+
color: ${t(colors.red[700], colors.red[400])};
307+
font-size: 0.875rem;
302308
`,
303309
devtoolsPanelContainer: (
304310
panelLocation: TanStackDevtoolsConfig['panelLocation'],

packages/devtools/src/tabs/seo-tab/serp-preview.tsx

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createEffect, createSignal } from 'solid-js'
1+
import { createEffect, createMemo, createSignal, For } from 'solid-js'
22
import { useStyles } from '../../styles/use-styles'
33
import { useHeadChanges } from '../../hooks/use-head-changes'
44
import { 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+
6993
export 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

Comments
 (0)