Skip to content

Merch Shop / DS Update - New Social logos - #1105

Merged
tannerlinsley merged 2 commits into
mainfrom
codex/pull-ds-update-shop-improvements
Aug 4, 2026
Merged

Merch Shop / DS Update - New Social logos#1105
tannerlinsley merged 2 commits into
mainfrom
codex/pull-ds-update-shop-improvements

Conversation

@Abeuty

@Abeuty Abeuty commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Refresh brand assets, favicons, and shared site chrome.
  • Update design system components and documentation routes.
  • Improve shop browsing, product details, cart interactions, and supporting UI components.
  • Refine shared navigation, footer, homepage, and maintainer experiences.

Testing

Not run (not requested).

Summary by CodeRabbit

  • New Features

    • Added interactive brand asset pickers with previews, copying, and downloads.
    • Added expandable design-system navigation, responsive search inputs, and themed select controls.
    • Added mobile navigation authentication actions and stateful button-group examples.
    • Updated product details with a responsive bottom-sheet experience and previous/next navigation.
  • Improvements

    • Refined shop typography, colors, badges, product cards, and cart presentation.
    • Improved maintainer cards, accessibility, responsive layouts, and reduced-motion support.
    • Streamlined footer placement and updated shop branding to TanStack Merch.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: abb7e454-51d8-4c8a-8f10-6bb5d19044ec

📥 Commits

Reviewing files that changed from the base of the PR and between 00519ae and 86b457c.

📒 Files selected for processing (24)
  • src/components/LibraryLayout.tsx
  • src/components/MaintainerCard.tsx
  • src/components/Navbar.tsx
  • src/components/NavbarAuthControls.tsx
  • src/components/ds/BrandAssets.tsx
  • src/components/ds/DsKit.tsx
  • src/components/ds/ui/index.tsx
  • src/components/home/HomeNewsletterSection.tsx
  • src/components/shop/CartDrawer.tsx
  • src/components/shop/ui/Qty.tsx
  • src/routes/ads.tsx
  • src/routes/blog.index.tsx
  • src/routes/ds.buttons.tsx
  • src/routes/ds.eyebrow.tsx
  • src/routes/ds.tsx
  • src/routes/ethos.tsx
  • src/routes/index.tsx
  • src/routes/maintainers.tsx
  • src/routes/merch.tsx
  • src/routes/partners.$partner.tsx
  • src/routes/partners.railway.tsx
  • src/routes/shop.cart.tsx
  • src/routes/tenets.tsx
  • src/routes/workshops.tsx
🚧 Files skipped from review as they are similar to previous changes (23)
  • src/components/LibraryLayout.tsx
  • src/routes/tenets.tsx
  • src/components/NavbarAuthControls.tsx
  • src/routes/workshops.tsx
  • src/components/shop/CartDrawer.tsx
  • src/components/ds/DsKit.tsx
  • src/routes/shop.cart.tsx
  • src/routes/partners.$partner.tsx
  • src/components/ds/ui/index.tsx
  • src/components/home/HomeNewsletterSection.tsx
  • src/routes/blog.index.tsx
  • src/routes/maintainers.tsx
  • src/routes/index.tsx
  • src/components/MaintainerCard.tsx
  • src/components/shop/ui/Qty.tsx
  • src/routes/partners.railway.tsx
  • src/routes/ethos.tsx
  • src/routes/ds.tsx
  • src/routes/ds.eyebrow.tsx
  • src/routes/ads.tsx
  • src/routes/ds.buttons.tsx
  • src/components/Navbar.tsx
  • src/routes/merch.tsx

📝 Walkthrough

Walkthrough

The PR updates footer placement, responsive navigation, design-system navigation and controls, brand asset tooling, and shop tokens, product cards, and product drawer interactions.

Changes

Site shell and navigation

Layer / File(s) Summary
Footer placement and layout
src/components/Footer.tsx, src/components/LibraryLayout.tsx, src/routes/__root.tsx, src/routes/*
Footer rendering moves to the root layout. Duplicate route-level footers are removed, and the inner footer wrapper is simplified.
Responsive navbar authentication
src/components/Navbar.tsx, src/components/NavbarAuthControls.tsx
Mobile authentication controls are lazy-loaded. Desktop-only controls and mobile navigation typography are updated.
Homepage and maintainer presentation
src/routes/index.tsx, src/components/MaintainerCard.tsx
Responsive hero and maintainer card styling is updated.

Design-system navigation and components

Layer / File(s) Summary
Interactive brand asset gallery
src/components/ds/BrandAssets.tsx
Brand and social assets support selection, previews, copying, and downloads.
Design-system sections and controls
src/components/ds/DsKit.tsx, src/components/ds/ui/index.tsx
Sections receive generated IDs and custom classes. FormSelect and SearchInput are added.
Subsection navigation
src/components/ds/ds-nav.ts, src/routes/ds.tsx
The sidebar supports subsection metadata, expandable groups, hash navigation, and cancellable scrolling.
Design-system examples and route consolidation
src/components/ButtonGroup.tsx, src/routes/ds.*
Examples demonstrate pressed buttons, maintainer cards, themed selects, and search variants. The maintainers route redirects to the avatar section.

Shop presentation and product flow

Layer / File(s) Summary
Shop tokens and color utilities
src/styles/app.css, src/styles/shop.css, src/utils/shop-color.ts
Shop typography, colors, gradients, motion tokens, and product color utilities are centralized.
Shared shop controls and typography
src/components/shop/*, src/components/shop/ui/*
Shop components use shared typography, shadows, gradients, and color utilities.
Product cards and browse branding
src/components/shop/ProductCard.tsx, src/routes/-shop-browse.tsx
The newest product is marked explicitly. Product swatches use shared color resolution, and the browse hero uses TanStack Merch branding.
Product drawer sheet flow
src/components/shop/ProductDrawer.tsx, src/styles/shop.css
The product drawer becomes a responsive bottom sheet with prefetching, retained transitions, horizontal thumbnails, shared controls, and reveal animations.
Shop route styling and metadata
src/routes/shop.*
Shop route typography and metadata use shared design-system tokens.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Reviewer
  participant DsSidebar
  participant RouterLocation
  participant DsSection
  Reviewer->>DsSidebar: Select subsection link
  DsSidebar->>RouterLocation: Update URL hash
  DsSidebar->>DsSection: Scroll to generated section ID
  DsSection-->>Reviewer: Show selected subsection
Loading
sequenceDiagram
  participant ProductDrawer
  participant ReactQuery
  participant ProductContent
  participant ShopControls
  ProductDrawer->>ReactQuery: Prefetch neighboring products
  ReactQuery-->>ProductDrawer: Return cached product data
  ProductDrawer->>ProductContent: Preserve and animate product content
  ProductContent->>ShopControls: Render shared product controls
  ShopControls-->>ProductDrawer: Report selection and cart actions
Loading

Possibly related PRs

Suggested reviewers: sukvvon

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies the merch shop and design-system updates, including the brand asset changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/pull-ds-update-shop-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
tanstack-com 86b457c Commit Preview URL

Branch Preview URL
Aug 03 2026, 08:21 PM

…shop-improvements

# Conflicts:
#	src/components/MaintainerCard.tsx
#	src/components/Navbar.tsx
#	src/components/NavbarAuthControls.tsx
#	src/components/ds/BrandAssets.tsx
#	src/components/ds/ui/index.tsx
#	src/routes/blog.index.tsx
#	src/routes/maintainers.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/shop/ProductCard.tsx (1)

20-34: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the collection-level "New" badge on collections routes.

ProductCard defaults isNew to false, and shop.collections.$handle.tsx calls it without that prop; only -shop-browse.tsx computes one product as newestProduct and passes it. If products shown under product.publishedAt should show "New", compute that value in the collection route with the same published-date logic before rendering ProductCard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shop/ProductCard.tsx` around lines 20 - 34, Update the
collection route’s ProductCard rendering to compute isNew using the same
published-date logic as newestProduct in -shop-browse.tsx, based on
product.publishedAt, and pass that value explicitly so the collection-level
“New” badge is preserved.
🧹 Nitpick comments (3)
src/components/ds/BrandAssets.tsx (1)

197-212: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the shared asset-URL logic.

BrandLogoPicker and SocialLogoPicker duplicate the same format-to-extension mapping and the same assetName/href composition. CopyAssetButton and the download Button blocks are also near-identical between the two pickers. A small shared helper for the extension plus a shared AssetActions component would remove the duplication and keep the two pickers in sync when a new format is added.

Also applies to: 396-404

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ds/BrandAssets.tsx` around lines 197 - 212, Extract the
duplicated format-to-extension and assetName/href construction used by
BrandLogoPicker and SocialLogoPicker into shared helpers, then introduce a
shared AssetActions component for the duplicated CopyAssetButton and download
Button blocks. Update both pickers to use these shared symbols so future format
additions and action behavior remain synchronized.
src/components/ButtonGroup.tsx (1)

18-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use Tailwind v4 direct-child and aria-* variants.

Replace the arbitrary variant with *:aria-pressed:border-transparent *:aria-pressed:bg-text-primary *:aria-pressed:text-background-default *:aria-pressed:shadow-sm for a cleaner supported selector when applying these styles to pressed children.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ButtonGroup.tsx` at line 18, Update the pressed-child class
variants in ButtonGroup to use Tailwind v4 direct-child aria variants: replace
each [&>[aria-pressed=true]] prefix with *:aria-pressed while preserving the
existing border, background, text, and shadow utilities.
src/components/shop/ProductDrawer.tsx (1)

645-656: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Sanitize descriptionHtml before injecting it.

dangerouslySetInnerHTML={{ __html: product.descriptionHtml }} renders Shopify product description HTML without sanitization. This bypasses React's built-in XSS protection. If the description content is ever edited by a lower-trust staff account or the CMS content is compromised, this becomes a stored-XSS vector.

Sanitize product.descriptionHtml with a library such as DOMPurify before rendering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shop/ProductDrawer.tsx` around lines 645 - 656, Sanitize
product.descriptionHtml with the project’s approved HTML sanitization library,
such as DOMPurify, before passing it to dangerouslySetInnerHTML in the product
description block of ProductDrawer. Keep the existing conditional rendering and
styling unchanged, and inject only the sanitized HTML.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ds/BrandAssets.tsx`:
- Around line 133-161: Update the image-loading effect in DissolvingLogoPreview
by adding an image.onerror handler alongside image.onload. After confirming the
request is still active, commit the requested {src, alt} to current and clear
any incoming image/transition state so the preview matches the selected asset
even when loading fails.

In `@src/components/ds/ui/index.tsx`:
- Around line 503-522: Update the input props and non-progressive search-field
rendering around the visible `progressive` branch to provide a default
accessible `aria-label` for the search input, while allowing callers to override
it. Ensure the default is used when no label is supplied and preserve any
explicitly provided `aria-label`.

In `@src/components/MaintainerCard.tsx`:
- Line 226: Update the card variant social-links layout class to use
justify-start instead of justify-center, aligning its icons with the
left-aligned content while preserving the existing wrapping, centering, and gap
classes.

In `@src/components/shop/ProductDrawer.tsx`:
- Around line 128-132: Replace the render-time mutations of hasOpened in
ProductDrawer with state and the established derived-state-during-render pattern
used nearby. Update the state when isOpen and prefetchedProduct indicate the
first open, reset it when the drawer closes without displayHandle, and derive
isAnimatedOpen from the state while preserving the existing visibility behavior.

In `@src/routes/__root.tsx`:
- Around line 323-330: Update the non-hideNavbar branch in the route component
so the children are wrapped in a flex-growing element before rendering Footer,
allowing short route content to consume remaining viewport height and keeping
the footer at the bottom. Leave the hideNavbar branch unchanged.

In `@src/routes/ds.avatar.tsx`:
- Around line 91-98: Align the third responsive grid breakpoint between the
ComponentPreview className and its code sample, updating the mismatched xl/lg
utility so both use the same breakpoint while preserving the other grid classes.

In `@src/routes/ds.buttons.tsx`:
- Around line 286-292: Update the documented ButtonPreview snippet in the
surrounding component to use the same capitalized period values as PERIODS and
SegmentedButtonGroup: “Day”, “Week”, and “Month”. Keep the aria-pressed
comparisons aligned with the actual period values.

In `@src/routes/ds.maintainers.tsx`:
- Around line 3-7: Update the redirect options in the Route beforeLoad handler
to set replace: true, ensuring the redirect from /ds/maintainers replaces its
history entry while preserving the existing destination and hash.

In `@src/routes/ds.tsx`:
- Around line 159-171: Update the subsection navigation around the sidebar link
and navigateToSection: in src/routes/ds.tsx lines 159-171, replace the plain
anchor with the router Link using item.to and the subsection hash, retaining the
custom scroll handler only for same-page navigation; in src/routes/ds.tsx lines
46-47, replace window.history.pushState with router navigation that sets the
hash so router location and the address bar remain synchronized.

In `@src/styles/shop.css`:
- Around line 42-51: Update the background-color declaration in .shop-merch-mark
to use the lowercase CSS keyword currentcolor, preserving the existing styling
and other declarations.

---

Outside diff comments:
In `@src/components/shop/ProductCard.tsx`:
- Around line 20-34: Update the collection route’s ProductCard rendering to
compute isNew using the same published-date logic as newestProduct in
-shop-browse.tsx, based on product.publishedAt, and pass that value explicitly
so the collection-level “New” badge is preserved.

---

Nitpick comments:
In `@src/components/ButtonGroup.tsx`:
- Line 18: Update the pressed-child class variants in ButtonGroup to use
Tailwind v4 direct-child aria variants: replace each [&>[aria-pressed=true]]
prefix with *:aria-pressed while preserving the existing border, background,
text, and shadow utilities.

In `@src/components/ds/BrandAssets.tsx`:
- Around line 197-212: Extract the duplicated format-to-extension and
assetName/href construction used by BrandLogoPicker and SocialLogoPicker into
shared helpers, then introduce a shared AssetActions component for the
duplicated CopyAssetButton and download Button blocks. Update both pickers to
use these shared symbols so future format additions and action behavior remain
synchronized.

In `@src/components/shop/ProductDrawer.tsx`:
- Around line 645-656: Sanitize product.descriptionHtml with the project’s
approved HTML sanitization library, such as DOMPurify, before passing it to
dangerouslySetInnerHTML in the product description block of ProductDrawer. Keep
the existing conditional rendering and styling unchanged, and inject only the
sanitized HTML.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dc0f9a33-ff51-4b12-828c-9ffed09e7ea1

📥 Commits

Reviewing files that changed from the base of the PR and between bf00919 and 00519ae.

⛔ Files ignored due to path filters (52)
  • public/android-chrome-192x192.png is excluded by !**/*.png
  • public/android-chrome-512x512.png is excluded by !**/*.png
  • public/apple-touch-icon.png is excluded by !**/*.png
  • public/favicon-16x16.png is excluded by !**/*.png
  • public/favicon-32x32.png is excluded by !**/*.png
  • public/favicon-dark.svg is excluded by !**/*.svg
  • public/favicon-light.svg is excluded by !**/*.svg
  • public/favicon.ico is excluded by !**/*.ico
  • public/favicon.png is excluded by !**/*.png
  • public/images/brand/social/mark-green.svg is excluded by !**/*.svg
  • public/images/brand/social/mark-green@2x.png is excluded by !**/*.png
  • public/images/brand/social/mark-ocean.svg is excluded by !**/*.svg
  • public/images/brand/social/mark-ocean@2x.png is excluded by !**/*.png
  • public/images/brand/social/mark-purple.svg is excluded by !**/*.svg
  • public/images/brand/social/mark-purple@2x.png is excluded by !**/*.png
  • public/images/brand/social/mark-yellow.svg is excluded by !**/*.svg
  • public/images/brand/social/mark-yellow@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-dark.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-dark@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-green.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-green@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-light.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-light@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-ocean.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-ocean@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-purple.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-purple@2x.png is excluded by !**/*.png
  • public/images/brand/social/naked-mark-yellow.svg is excluded by !**/*.svg
  • public/images/brand/social/naked-mark-yellow@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-dark.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-dark@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-green.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-green@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-light.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-light@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-ocean.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-ocean@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-purple.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-purple@2x.png is excluded by !**/*.png
  • public/images/brand/social/stacked-yellow.svg is excluded by !**/*.svg
  • public/images/brand/social/stacked-yellow@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-emblem-black@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-emblem-charcoal@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-emblem-cream@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-emblem-white@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-landscape-black@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-landscape-charcoal@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-landscape-white@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-stacked-black@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-stacked-charcoal@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-stacked-cream@2x.png is excluded by !**/*.png
  • public/images/brand/tanstack-stacked-white@2x.png is excluded by !**/*.png
📒 Files selected for processing (54)
  • src/components/ButtonGroup.tsx
  • src/components/Footer.tsx
  • src/components/LibraryLayout.tsx
  • src/components/MaintainerCard.tsx
  • src/components/Navbar.tsx
  • src/components/NavbarAuthControls.tsx
  • src/components/ds/BrandAssets.tsx
  • src/components/ds/DsKit.tsx
  • src/components/ds/ds-nav.ts
  • src/components/ds/ui/index.tsx
  • src/components/home/HomeNewsletterSection.tsx
  • src/components/shop/CartDrawer.tsx
  • src/components/shop/ProductCard.tsx
  • src/components/shop/ProductDrawer.tsx
  • src/components/shop/ShopDropCard.tsx
  • src/components/shop/ShopNote.tsx
  • src/components/shop/ShopSpecs.tsx
  • src/components/shop/ShopStrip.tsx
  • src/components/shop/ui/Badge.tsx
  • src/components/shop/ui/Chip.tsx
  • src/components/shop/ui/Crumb.tsx
  • src/components/shop/ui/Input.tsx
  • src/components/shop/ui/Qty.tsx
  • src/components/shop/ui/Select.tsx
  • src/routes/-shop-browse.tsx
  • src/routes/__root.tsx
  • src/routes/ads.tsx
  • src/routes/blog.index.tsx
  • src/routes/ds.avatar.tsx
  • src/routes/ds.buttons.tsx
  • src/routes/ds.eyebrow.tsx
  • src/routes/ds.inputs.tsx
  • src/routes/ds.maintainers.tsx
  • src/routes/ds.tsx
  • src/routes/ethos.tsx
  • src/routes/index.tsx
  • src/routes/maintainers.tsx
  • src/routes/merch.tsx
  • src/routes/partners.$partner.tsx
  • src/routes/partners.index.tsx
  • src/routes/partners.railway.tsx
  • src/routes/privacy.tsx
  • src/routes/shop.cart.tsx
  • src/routes/shop.collections.$handle.tsx
  • src/routes/shop.index.tsx
  • src/routes/shop.pages.$handle.tsx
  • src/routes/shop.policies.$handle.tsx
  • src/routes/shop.products.$handle.tsx
  • src/routes/tenets.tsx
  • src/routes/terms.tsx
  • src/routes/workshops.tsx
  • src/styles/app.css
  • src/styles/shop.css
  • src/utils/shop-color.ts
💤 Files with no reviewable changes (14)
  • src/routes/partners.index.tsx
  • src/components/home/HomeNewsletterSection.tsx
  • src/components/LibraryLayout.tsx
  • src/routes/tenets.tsx
  • src/routes/terms.tsx
  • src/routes/ethos.tsx
  • src/routes/maintainers.tsx
  • src/routes/partners.$partner.tsx
  • src/routes/privacy.tsx
  • src/routes/merch.tsx
  • src/routes/ads.tsx
  • src/routes/blog.index.tsx
  • src/routes/workshops.tsx
  • src/routes/partners.railway.tsx

Comment on lines +133 to +161
React.useEffect(() => {
if (src === current.src) return

const activeRequest = ++requestId.current
const image = new Image()
image.onload = () => {
if (activeRequest !== requestId.current) return

if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
setCurrent({ src, alt })
setIncoming(null)
setIncomingVisible(false)
return
}

setIncoming({ src, alt })
setIncomingVisible(false)
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
if (activeRequest === requestId.current) setIncomingVisible(true)
})
})
}
image.src = src

return () => {
requestId.current += 1
}
}, [alt, current.src, src])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle image load failures in DissolvingLogoPreview.

The effect only sets image.onload. If the requested asset fails to load, no state update occurs. The preview then keeps the previous logo while the footer label, the copy action, and the download link already point to the new selection. The user sees a mismatch with no feedback.

Add an onerror handler that commits the new source, so the broken-image state matches the labels.

🛠️ Proposed fix
     const activeRequest = ++requestId.current
     const image = new Image()
     image.onload = () => {
       if (activeRequest !== requestId.current) return
 
       if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
         setCurrent({ src, alt })
         setIncoming(null)
         setIncomingVisible(false)
         return
       }
 
       setIncoming({ src, alt })
       setIncomingVisible(false)
       window.requestAnimationFrame(() => {
         window.requestAnimationFrame(() => {
           if (activeRequest === requestId.current) setIncomingVisible(true)
         })
       })
     }
+    image.onerror = () => {
+      if (activeRequest !== requestId.current) return
+      setCurrent({ src, alt })
+      setIncoming(null)
+      setIncomingVisible(false)
+    }
     image.src = src
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
React.useEffect(() => {
if (src === current.src) return
const activeRequest = ++requestId.current
const image = new Image()
image.onload = () => {
if (activeRequest !== requestId.current) return
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
setCurrent({ src, alt })
setIncoming(null)
setIncomingVisible(false)
return
}
setIncoming({ src, alt })
setIncomingVisible(false)
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
if (activeRequest === requestId.current) setIncomingVisible(true)
})
})
}
image.src = src
return () => {
requestId.current += 1
}
}, [alt, current.src, src])
React.useEffect(() => {
if (src === current.src) return
const activeRequest = ++requestId.current
const image = new Image()
image.onload = () => {
if (activeRequest !== requestId.current) return
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
setCurrent({ src, alt })
setIncoming(null)
setIncomingVisible(false)
return
}
setIncoming({ src, alt })
setIncomingVisible(false)
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
if (activeRequest === requestId.current) setIncomingVisible(true)
})
})
}
image.onerror = () => {
if (activeRequest !== requestId.current) return
setCurrent({ src, alt })
setIncoming(null)
setIncomingVisible(false)
}
image.src = src
return () => {
requestId.current += 1
}
}, [alt, current.src, src])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ds/BrandAssets.tsx` around lines 133 - 161, Update the
image-loading effect in DissolvingLogoPreview by adding an image.onerror handler
alongside image.onload. After confirming the request is still active, commit the
requested {src, alt} to current and clear any incoming image/transition state so
the preview matches the selected asset even when loading fails.

Comment on lines +503 to +522
if (!progressive) {
return (
<label
className={twMerge(
'flex w-full items-center border border-border-default bg-background-surface text-text-muted transition-[border-color,box-shadow] duration-150 focus-within:border-border-focus focus-within:text-text-primary focus-within:ring-2 focus-within:ring-border-focus/40 motion-reduce:transition-none',
size === 'large'
? 'min-h-14 gap-3 rounded-xl px-4'
: 'h-10 gap-2.5 rounded-lg px-3',
)}
>
<MagnifyingGlass
size={size === 'large' ? 21 : 18}
weight="bold"
aria-hidden="true"
className="shrink-0"
/>
{input}
</label>
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Give the search field an accessible name.

The non-progressive branch wraps the input in a <label> that contains only the decorative icon. The icon carries aria-hidden="true", so the label exposes no text. Screen-reader users then depend on the placeholder for the accessible name, which is not a reliable label. The ds.inputs.tsx examples pass only placeholder.

Set a default aria-label on the input so every consumer gets a name, and allow callers to override it.

♿ Proposed fix
     const input = (
       <input
         ref={inputRef}
         type="search"
+        aria-label={props['aria-label'] ?? 'Search'}
         className={twMerge(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ds/ui/index.tsx` around lines 503 - 522, Update the input
props and non-progressive search-field rendering around the visible
`progressive` branch to provide a default accessible `aria-label` for the search
input, while allowing callers to override it. Ensure the default is used when no
label is supplied and preserve any explicitly provided `aria-label`.

className={
variant === 'card'
? 'flex flex-wrap items-center justify-center gap-6'
? 'flex flex-wrap items-center justify-center gap-4 sm:gap-6'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align the card social links with the left-aligned content.

Line 409 sets the content column to items-start and Line 411 sets the name to text-left. The card variant row still uses justify-center, so the icons center under a left-aligned name. Use justify-start for the card variant.

🎨 Proposed fix
-          ? 'flex flex-wrap items-center justify-center gap-4 sm:gap-6'
+          ? 'flex flex-wrap items-center justify-start gap-4 sm:gap-6'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
? 'flex flex-wrap items-center justify-center gap-4 sm:gap-6'
? 'flex flex-wrap items-center justify-start gap-4 sm:gap-6'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/MaintainerCard.tsx` at line 226, Update the card variant
social-links layout class to use justify-start instead of justify-center,
aligning its icons with the left-aligned content while preserving the existing
wrapping, centering, and gap classes.

Comment on lines +128 to +132
// Wait for data on the first open, but keep the sheet visible while products swap.
const hasOpened = React.useRef(false)
if (isOpen && prefetchedProduct) hasOpened.current = true
if (!isOpen && !displayHandle) hasOpened.current = false
const isAnimatedOpen = isOpen && hasOpened.current

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Ref mutated during render can leak stale state across discarded renders.

hasOpened.current is written directly in the render body (lines 130-131), not inside an event handler or effect. React can discard or replay a render (for example under Strict Mode double-invocation or interrupted concurrent rendering), so a mutation performed during a render that never commits can still leak into subsequent renders. isAnimatedOpen at line 132 then derives from a ref value that may not correspond to the actually-committed render.

The file already uses the safe "derived state during render" pattern with setState at lines 89-92 and 122-125. Convert hasOpened to state using the same pattern for consistency and correctness.

🔧 Proposed fix using state instead of a mutated ref
-  const hasOpened = React.useRef(false)
-  if (isOpen && prefetchedProduct) hasOpened.current = true
-  if (!isOpen && !displayHandle) hasOpened.current = false
-  const isAnimatedOpen = isOpen && hasOpened.current
+  const [hasOpened, setHasOpened] = React.useState(false)
+  if (isOpen && prefetchedProduct && !hasOpened) setHasOpened(true)
+  if (!isOpen && !displayHandle && hasOpened) setHasOpened(false)
+  const isAnimatedOpen = isOpen && hasOpened
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Wait for data on the first open, but keep the sheet visible while products swap.
const hasOpened = React.useRef(false)
if (isOpen && prefetchedProduct) hasOpened.current = true
if (!isOpen && !displayHandle) hasOpened.current = false
const isAnimatedOpen = isOpen && hasOpened.current
// Wait for data on the first open, but keep the sheet visible while products swap.
const [hasOpened, setHasOpened] = React.useState(false)
if (isOpen && prefetchedProduct && !hasOpened) setHasOpened(true)
if (!isOpen && !displayHandle && hasOpened) setHasOpened(false)
const isAnimatedOpen = isOpen && hasOpened
🧰 Tools
🪛 React Doctor (0.9.1)

[error] 130-130: This ref is mutated during render. React can replay or discard render work, so the mutation can leak from UI that never commits.

Move ref writes into an event handler or effect. Render must stay pure because React can replay or discard it. The predictable null-guarded lazy initialization pattern remains supported.

(no-ref-current-in-render)


[error] 131-131: This ref is mutated during render. React can replay or discard render work, so the mutation can leak from UI that never commits.

Move ref writes into an event handler or effect. Render must stay pure because React can replay or discard it. The predictable null-guarded lazy initialization pattern remains supported.

(no-ref-current-in-render)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shop/ProductDrawer.tsx` around lines 128 - 132, Replace the
render-time mutations of hasOpened in ProductDrawer with state and the
established derived-state-during-render pattern used nearby. Update the state
when isOpen and prefetchedProduct indicate the first open, reset it when the
drawer closes without displayHandle, and derive isAnimatedOpen from the state
while preserving the existing visibility behavior.

Source: Linters/SAST tools

Comment thread src/routes/__root.tsx
Comment on lines +323 to +330
{hideNavbar ? (
children
) : (
<Navbar>
{children}
<Footer />
</Navbar>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the footer at the bottom of short routes.

Navbar renders its children in a flex-1 flex flex-col wrapper at src/components/Navbar.tsx lines 740-742. The footer follows short route content inside that wrapper, so unused viewport height remains below the footer. Wrap the route content in a flex-growing element before Footer.

Proposed fix
 <Navbar>
-  {children}
+  <div className="flex flex-1 flex-col">
+    {children}
+  </div>
   <Footer />
 </Navbar>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{hideNavbar ? (
children
) : (
<Navbar>
{children}
<Footer />
</Navbar>
)}
{hideNavbar ? (
children
) : (
<Navbar>
<div className="flex flex-1 flex-col">
{children}
</div>
<Footer />
</Navbar>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/__root.tsx` around lines 323 - 330, Update the non-hideNavbar
branch in the route component so the children are wrapped in a flex-growing
element before rendering Footer, allowing short route content to consume
remaining viewport height and keeping the footer at the bottom. Leave the
hideNavbar branch unchanged.

Comment thread src/routes/ds.avatar.tsx
Comment on lines +91 to +98
<ComponentPreview
className="grid justify-items-center gap-6 sm:grid-cols-2 xl:grid-cols-3"
code={`<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{maintainers.map((maintainer) => (
<MaintainerCard key={maintainer.github} maintainer={maintainer} />
))}
</div>`}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The documented snippet does not match the rendered grid.

The code sample uses grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3. The rendered preview uses grid justify-items-center gap-6 sm:grid-cols-2 xl:grid-cols-3. A design-system page should show the classes it demonstrates, otherwise a reader copies a different breakpoint set than the one shown.

Align the third breakpoint in both places.

📝 Proposed fix
-          code={`<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
+          code={`<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-3">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<ComponentPreview
className="grid justify-items-center gap-6 sm:grid-cols-2 xl:grid-cols-3"
code={`<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{maintainers.map((maintainer) => (
<MaintainerCard key={maintainer.github} maintainer={maintainer} />
))}
</div>`}
>
<ComponentPreview
className="grid justify-items-center gap-6 sm:grid-cols-2 xl:grid-cols-3"
code={`<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-3">
{maintainers.map((maintainer) => (
<MaintainerCard key={maintainer.github} maintainer={maintainer} />
))}
</div>`}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/ds.avatar.tsx` around lines 91 - 98, Align the third responsive
grid breakpoint between the ComponentPreview className and its code sample,
updating the mismatched xl/lg utility so both use the same breakpoint while
preserving the other grid classes.

Comment thread src/routes/ds.buttons.tsx
Comment on lines 286 to 292
<ButtonPreview
code={`<ButtonGroup>
<Button variant="ghost" rounded="none">Day</Button>
<Button variant="ghost" rounded="none">Week</Button>
<Button variant="ghost" rounded="none">Month</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'day'}>Day</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'week'}>Week</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'month'}>Month</Button>
</ButtonGroup>`}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The documented snippet uses the wrong case for the period values.

The sample compares period === 'day', 'week', and 'month'. PERIODS at Line 87 holds 'Day', 'Week', and 'Month'. A reader who copies the snippet gets aria-pressed={false} on every button. Match the sample to SegmentedButtonGroup.

📝 Proposed fix
           code={`<ButtonGroup>
-  <Button variant="ghost" rounded="none" aria-pressed={period === 'day'}>Day</Button>
-  <Button variant="ghost" rounded="none" aria-pressed={period === 'week'}>Week</Button>
-  <Button variant="ghost" rounded="none" aria-pressed={period === 'month'}>Month</Button>
+  <Button variant="ghost" rounded="none" aria-pressed={period === 'Day'}>Day</Button>
+  <Button variant="ghost" rounded="none" aria-pressed={period === 'Week'}>Week</Button>
+  <Button variant="ghost" rounded="none" aria-pressed={period === 'Month'}>Month</Button>
 </ButtonGroup>`}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<ButtonPreview
code={`<ButtonGroup>
<Button variant="ghost" rounded="none">Day</Button>
<Button variant="ghost" rounded="none">Week</Button>
<Button variant="ghost" rounded="none">Month</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'day'}>Day</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'week'}>Week</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'month'}>Month</Button>
</ButtonGroup>`}
>
<ButtonPreview
code={`<ButtonGroup>
<Button variant="ghost" rounded="none" aria-pressed={period === 'Day'}>Day</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'Week'}>Week</Button>
<Button variant="ghost" rounded="none" aria-pressed={period === 'Month'}>Month</Button>
</ButtonGroup>`}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/ds.buttons.tsx` around lines 286 - 292, Update the documented
ButtonPreview snippet in the surrounding component to use the same capitalized
period values as PERIODS and SegmentedButtonGroup: “Day”, “Week”, and “Month”.
Keep the aria-pressed comparisons aligned with the actual period values.

Comment on lines 3 to 7
export const Route = createFileRoute('/ds/maintainers')({
component: MaintainersPage,
head: () => ({
meta: seo({
title: 'Maintainers | TanStack Design System',
description:
'The shared maintainer card used for core teams, instructors, and library maintainers across TanStack.',
}),
}),
beforeLoad: () => {
throw redirect({ to: '/ds/avatar', hash: 'maintainer-card' })
},
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

TanStack Router redirect replace option beforeLoad history stack

💡 Result:

In TanStack Router, the redirect function used within beforeLoad accepts the same navigation options as the navigate function, including the replace option [1][2][3]. To control the browser history stack when performing a redirect, you can pass { replace: true } in the options object [1][2][4]. Setting replace to true will cause the router to replace the current entry in the history stack instead of pushing a new one, which is particularly useful for avoiding history pollution in authentication flows [1][2][4]. Example usage within a beforeLoad hook: throw redirect({ to: '/login', replace: true, // Replaces current history entry }) The redirect function, when used with throw: true (or simply thrown as an object, which is the standard pattern), allows for type-safe and declarative navigation triggered during the route loading process [5][6][7][3]. Because redirect extends NavigateOptions, all standard navigation features—such as params, search, and state management—are fully supported alongside the history-controlling replace property [3].

Citations:


Set replace: true on the redirect.

This route throws a redirect from beforeLoad; without replace, the browser history keeps /ds/maintainers below /ds/avatar#maintainer-card, so Back can return to the same redirect source. Set replace: true to replace the beforeLoad history entry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/ds.maintainers.tsx` around lines 3 - 7, Update the redirect
options in the Route beforeLoad handler to set replace: true, ensuring the
redirect from /ds/maintainers replaces its history entry while preserving the
existing destination and hash.

Comment thread src/routes/ds.tsx
Comment on lines +159 to +171
<a
href={`${item.to}#${toDsSectionId(subsection)}`}
onClick={(event) =>
navigateToSection(
event,
item.to,
toDsSectionId(subsection),
)
}
className="block rounded-md px-2 py-1 text-xs text-text-muted hover:bg-background-subtle hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus"
>
{subsection}
</a>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The design-system sidebar navigates outside TanStack Router. The subsection links use a plain <a href> and the same-page handler writes the hash with window.history.pushState. Both bypass the router, so cross-page clicks trigger a full document load and the router's location state never learns the new hash. Route both paths through the router.

  • src/routes/ds.tsx#L159-L171: replace the <a href> with the router Link, passing to={item.to} and hash={toDsSectionId(subsection)}, and keep the custom scroll handler only for the same-page case.
  • src/routes/ds.tsx#L46-L47: replace window.history.pushState(null, '', '#' + sectionId) with a router navigation that sets the hash, so useLocation() and the address bar stay consistent.
📍 Affects 1 file
  • src/routes/ds.tsx#L159-L171 (this comment)
  • src/routes/ds.tsx#L46-L47
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/ds.tsx` around lines 159 - 171, Update the subsection navigation
around the sidebar link and navigateToSection: in src/routes/ds.tsx lines
159-171, replace the plain anchor with the router Link using item.to and the
subsection hash, retaining the custom scroll handler only for same-page
navigation; in src/routes/ds.tsx lines 46-47, replace window.history.pushState
with router navigation that sets the hash so router location and the address bar
remain synchronized.

Comment thread src/styles/shop.css
Comment on lines +42 to +51
.shop-merch-mark {
display: inline-block;
width: 0.82em;
height: 0.82em;
flex: none;
background-color: currentColor;
-webkit-mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;
mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the configured CSS keyword casing.

Line 47 fails Stylelint value-keyword-case. Replace currentColor with currentcolor.

Proposed fix
-  background-color: currentColor;
+  background-color: currentcolor;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.shop-merch-mark {
display: inline-block;
width: 0.82em;
height: 0.82em;
flex: none;
background-color: currentColor;
-webkit-mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;
mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;
.shop-merch-mark {
display: inline-block;
width: 0.82em;
height: 0.82em;
flex: none;
background-color: currentcolor;
-webkit-mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;
mask: url('/images/brand/tanstack-emblem-black.svg') center / contain
no-repeat;
🧰 Tools
🪛 Stylelint (17.14.1)

[error] 47-47: Expected "currentColor" to be "currentcolor" (value-keyword-case)

(value-keyword-case)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/styles/shop.css` around lines 42 - 51, Update the background-color
declaration in .shop-merch-mark to use the lowercase CSS keyword currentcolor,
preserving the existing styling and other declarations.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants