Weekend overhaul: SEO changes, query optimization, landing page, animations#97
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR refreshes the homepage UX and SEO metadata handling, and consolidates Sanity CMS queries while updating several UI components (office hours, sponsors, affiliated groups).
Changes:
- Reworked the homepage hero layout, sections ordering, and added a dedicated Sponsors section/component.
- Consolidated homepage-related Sanity queries into a single GROQ fetch, and added a global layout-level thumbnail meta tag emitter.
- UI/UX polish: sticky time column in office hours schedule, typography styling for rich text, and updated theme tokens/animation timing.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/routes/+page.svelte | Homepage layout/section restructure; adds Sponsors section and updates hero + office hours copy. |
| src/routes/+page.server.ts | Consolidates CMS queries into one combined GROQ fetch for homepage/office hours/sponsors. |
| src/routes/+layout.svelte | Adds PageThumbnail to emit OG/Twitter image meta tags from layout data. |
| src/routes/+layout.server.ts | New layout server load to fetch a sitewide thumbnail from Sanity. |
| src/routes/+error.svelte | Adjusts error page copy formatting (adds a line break). |
| src/components/officehour/OHSchedule.svelte | Adds sticky styling for the time column/header in the schedule grid. |
| src/components/officehour/OHBlock.svelte | Office hour block styling adjustments. |
| src/components/layout/SeoMetaTags.svelte | Removes embedded default thumbnail meta tags (now handled by PageThumbnail). |
| src/components/layout/PageThumbnail.svelte | New component that injects OG/Twitter image meta tags. |
| src/components/homepage/Sponsors.svelte | New Sponsors section UI for homepage. |
| src/components/homepage/AffiliatedGroups.svelte | Updates group content/icons and refactors the card layout + links UI. |
| src/components/RichText.svelte | Applies shared .typography styling wrapper. |
| src/app.css | Adds new color tokens and adjusts wiggle animation timing/behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <meta property="og:image" content={thumbnail} /> | ||
| <meta property="twitter:image" content={thumbnail} /> |
There was a problem hiding this comment.
PageThumbnail always emits og:image / twitter:image meta tags even when thumbnail is an empty string. If the thumbnail is missing, it’s better to omit these tags or provide a non-empty default URL to avoid emitting empty SEO metadata.
| <meta property="og:image" content={thumbnail} /> | |
| <meta property="twitter:image" content={thumbnail} /> | |
| {#if thumbnail} | |
| <meta property="og:image" content={thumbnail} /> | |
| <meta property="twitter:image" content={thumbnail} /> | |
| {/if} |
| {#each sponsors as sponsor} | ||
| <Link href={sponsor.url} external> | ||
| <div | ||
| class="bg-ecsess-950 border-ecsess-800 hover:border-ecsess-700 group flex h-32 w-sm items-center justify-center rounded-lg border p-4 transition-all hover:shadow-lg" |
There was a problem hiding this comment.
w-sm is not a standard Tailwind width utility (likely meant max-w-sm or a fixed w-*). As-is, it will be ignored and the sponsor card width will collapse to content. Use a valid width utility (or define a custom width token) to make the layout deterministic.
| class="bg-ecsess-950 border-ecsess-800 hover:border-ecsess-700 group flex h-32 w-sm items-center justify-center rounded-lg border p-4 transition-all hover:shadow-lg" | |
| class="bg-ecsess-950 border-ecsess-800 hover:border-ecsess-700 group flex h-32 w-64 items-center justify-center rounded-lg border p-4 transition-all hover:shadow-lg" |
|
|
||
| <div | ||
| class="bg-ecsess-100 text-ecsess-900 hover:bg-ecsess-200 border-ecsess-300 grid h-full place-content-center rounded-md border text-center shadow-md transition-all hover:shadow-lg" | ||
| class="bg-ecsess-100 text-ecsess-900 hover:bg-ecsess-200 grid h-full place-content-center rounded-md border-transparent text-center shadow-md transition-all hover:shadow-lg" |
There was a problem hiding this comment.
border-transparent has no effect here because border (border-width) was removed from the class list. If the intent is no border, drop border-transparent; if the intent is an invisible border to prevent layout shift on hover, add border back.
| class="bg-ecsess-100 text-ecsess-900 hover:bg-ecsess-200 grid h-full place-content-center rounded-md border-transparent text-center shadow-md transition-all hover:shadow-lg" | |
| class="bg-ecsess-100 text-ecsess-900 hover:bg-ecsess-200 grid h-full place-content-center rounded-md text-center shadow-md transition-all hover:shadow-lg" |
|
|
||
| const sponsorQuery = `*[_type=="sponsors"]{ | ||
| const homepageQuery = `{ | ||
| "homepage": *[_type == "homepage"]{ |
There was a problem hiding this comment.
homepageQuery no longer selects description, but the load function still reads homepageResp.description and the HomepageCMSResponse type requires it. This will be undefined at runtime and likely a TypeScript mismatch. Either add "description": description[] back into the homepage projection, or remove description from the return value and update HomepageCMSResponse accordingly.
| "homepage": *[_type == "homepage"]{ | |
| "homepage": *[_type == "homepage"]{ | |
| "description": description[], |
| export const load = async () => { | ||
| return { thumbnail: (await getFromCMS(thumbnailQuery)).thumbnail }; | ||
| }; |
There was a problem hiding this comment.
This global +layout.server.ts load will run for every route; if the CMS request fails it will take down the entire site render. Consider wrapping the CMS fetch in try/catch and returning a safe fallback thumbnail (or omitting the tag) so non-home routes still work during CMS outages.
| {#each sponsors as sponsor} | ||
| <Link href={sponsor.url} external> | ||
| <div | ||
| class="bg-ecsess-950 border-ecsess-800 hover:border-ecsess-700 group flex h-32 w-sm items-center justify-center rounded-lg border p-4 transition-all hover:shadow-lg" | ||
| > | ||
| <img | ||
| src={sponsor.logo} | ||
| alt="{sponsor.name} Logo" | ||
| class="max-h-20 w-40 object-contain opacity-90 transition-opacity group-hover:opacity-100" |
There was a problem hiding this comment.
sponsor.url is coming directly from the CMS and is passed as href to Link without any validation of the URL scheme. If an attacker can control a sponsors entry in the CMS (or if that data is otherwise compromised), they could set url to a javascript: or other dangerous URI and trigger XSS in the context of your site when a user clicks the sponsor card. To harden this, ensure you validate or sanitize sponsor.url on the server or before rendering so only safe schemes like https/http are allowed, and ignore or replace anything else.
|
The CMS for homepage needs to be updated (remove description and FAQ) |
Made quite a lot of changes, will update the list