Replace the cabinet's hand-written heroicons-style SVG icon components with
the Remnawave panel's own icon family — Phosphor via react-icons/pi (Duotone).
All icons now live in a single central barrel (src/components/icons:
index + extended-icons + editor-icons, 144 icons); every feature file imports
from it instead of redefining inline SVGs (~440 icon defs removed).
- Add react-icons dependency
- Desktop nav (AppShell) now uses the central Phosphor icons, removing a
stroke-vs-duotone inconsistency the partial migration introduced
- Icons with custom props (SortIcon's direction, expandable chevrons) kept as
thin Phosphor wrappers; the RemnawaveIcon brand logo and animated SVGs
(checkmarks, spinners) are intentionally left as-is
- Restore the original per-call-site icon sizes wherever the centralized
default differed (211 call sites)
- htmlFor/id pairs for title, slug, read-time, excerpt and featured-image inputs
- add an ariaLabel prop to ColoredItemCombobox (applied to the trigger button) and
pass the category/tag labels so the comboboxes have an accessible name (WCAG 1.3.1/4.1.2)
- Add onDelete prop to ColoredItemCombobox with X button per item
- Wire up deleteCategory/deleteTag API calls in AdminNewsCreate
- Auto-clear selection if the deleted item was selected
- Spinner on delete, haptic feedback, i18n aria-label
- Fix tag using category_color instead of its own color when editing
- Add FormData auto-detection interceptor in client.ts (root cause of 422)
- Remove redundant Content-Type overrides from all 5 upload endpoints
- Fix falsy id check (id: 0 treated as null) with strict comparison
- Await invalidateQueries to prevent stale dropdown data
- ColoredItemCombobox component with search, color swatches, inline creation
- Replace text inputs with combobox dropdowns for category and tag selection
- API methods for categories/tags CRUD
- TypeScript types for NewsCategory, NewsTag
- i18n keys for combobox (ru, en)
- Register DOMPurify hooks at module init (not per sanitizeHtml call)
- Always set iframe allow attribute (not conditional on existing)
- Add AbortController to featured image upload for unmount cleanup
- Check defaultPrevented in React onDrop to prevent double upload with TipTap
- Remove explicit Content-Type header on upload (axios auto-sets boundary)
TipTap didn't recognize <video> tags without a custom node extension,
serializing them as escaped text. Also revert video src to allow HTTP
since request.base_url returns http:// behind reverse proxy.
- uploadCount: always decrement in finally (prevent permanent uploading state)
- AbortSignal: pass to actual HTTP request (cancel network, not just UI)
- Concurrent uploads: use Set<AbortController> instead of single ref
- DOMPurify hooks: scope inside sanitizeHtml() to avoid global pollution
- Video src: restrict to HTTPS only (was allowing HTTP)
- GIF: remove from accept attributes (backend rejects GIF)
- Ref mutation: move handleMediaUploadRef update to useEffect