ERA-13076: Remove approach to loading icons via one enormous sprite#1529
ERA-13076: Remove approach to loading icons via one enormous sprite#1529jeslefcourt wants to merge 11 commits into
Conversation
Replace SVG sprite-based icon loading with direct img tags using static SVG file URLs, simplifying the icon rendering pipeline and removing the preloaded sprite dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
luixlive
left a comment
There was a problem hiding this comment.
A couple small suggestions and a couple questions. Nothing hard-blocking, but worth taking a minute to think them through.
…mage files. Had a bit of a snowball effect into things impacted by cascading styles.
- Remove !important flags on svgs - Fixed icon colors in clusters and cluster popups changing when editing events before saving - Sanitize SVGs to avoid injection attacks
d4bcd19 to
3d4d8ab
Compare
JoshuaVulcan
left a comment
There was a problem hiding this comment.
Looks and feels pretty good so far! Will keep manually testing. My feedback on this review pass is around finishing off the refactor by making sure files and names are cleaned up.
| import mapboxgl from 'mapbox-gl'; | ||
|
|
||
| import { CLUSTER_CLICK_ZOOM_THRESHOLD, LAYER_IDS, SUBJECT_FEATURE_CONTENT_TYPE } from '../constants'; | ||
| import { calcSvgImageIconId } from '../MapImageFromSvgSpriteRenderer'; |
There was a problem hiding this comment.
It seems like MapImageFromSvgSpriteRenderer should be removed entirely, and the utility function to calculate image URLS lifted/shifted elsewhere.
There was a problem hiding this comment.
Lifted calcSvgImageIconId into src/utils/mapImages.js and repointed all importers (commit b10b38e). On removing MapImageFromSvgSpriteRenderer entirely: its default-export component is still load-bearing — it generates state.view.mapImages, which both EventsLayer's on-map symbol layer and the cluster markers consume — so fully removing it needs a separate migration of the on-map rendering path. I'd suggest tracking that as a follow-up rather than expanding this PR. Leaving this thread open for your call on the follow-up.
luixlive
left a comment
There was a problem hiding this comment.
Just a couple more comments and questions. I see now we are also updating the clusters when we have a locally edited event, which is a nice addition, but it's increasing the size of this PR considerably.
Once these comments are solved / responded, I'll be ready to approve. Still think we will need a special treatment from QA to make sure all icons render correctly and that clusters work and update correctly when we have local changes in an event that haven't been saved yet 👍 @AlanCalvillo
… rename - Refactor sanitizeSvg into named per-pass helpers for readability (no behavior change) - Rename DasIcon -> SvgIcon (component, directory, all importers); sprite is gone - Stabilize ClustersLayer update callback via refs so it stops re-firing on every eventStore change; effects now fire only on locallyEditedEvent / mapImages - Simplify getFeatureIcon (only priority is user-editable) and drop the dead eventStore threading through createClusterHTMLMarker/addNewClusterMarkers - Extract calcSvgImageIconId into src/utils/mapImages.js; repoint importers - Rename isLocally -> isLocallyEdited - LayerSelectorPopup: hide the list <img> on load error so missing sources don't render a broken-image glyph Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…prite-approach-to-loading-icons # Conflicts: # package.json # src/DasIcon/index.js # src/EventsLayer/index.js # src/LayerSelectorPopup/index.js # src/ReportManager/Header/styles.module.scss # yarn.lock
develop's eslint-9/react-hooks-7 upgrade flags render-phase ref mutation. These refs hold the latest values read only inside the async marker-update callback and effects, never during render; synchronous assignment guarantees they are current before any effect/callback runs. Add justified disables. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ster comment - Add SvgIcon tests covering the community events (extension-less) and community non-events (sprite-src .svg) icon endpoints - injectClass: trim merged class value to avoid leading/double spaces - sanitizeSvg: return null on DOMParser parsererror so the fallback engages - ClustersLayer: comment why imageLoaded uses the original-priority icon key for locally-edited features (markers are always recreated anyway) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
ReportTypeIconSpritefromApp.jsand the sprite-lookup logic fromDasIcon)DasIconnow fetches each icon's SVG from its static URL, sanitizes the markup, and inlines it (viadangerouslySetInnerHTML) so the SVG can inheritcurrentColorand be recolored by CSS. Sanitization strips hardcodedfill/strokecolors,<style>blocks, and class attributes, rewriting them tocurrentColor. Fetched icons are cached in a module-levelsvgCache<img>tag when the fetched resource is not SVG, and fortype === 'subjects'icons; falls back to the generic icon when an icon fails to loadsvgtoimg, and usesfilter: invert(1)to render icons white on dark headersJira
ERA-13076
Test plan
currentColor(e.g. white on dark headers)🤖 Generated with Claude Code