Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Refactor Admin Pages UI, standardize design system components, and fix JSX syntax errors#257

Open
Ali04web wants to merge 203 commits into
ebongard:mainfrom
Ali04web:feat/design-system-admin-pages
Open

Refactor Admin Pages UI, standardize design system components, and fix JSX syntax errors#257
Ali04web wants to merge 203 commits into
ebongard:mainfrom
Ali04web:feat/design-system-admin-pages

Conversation

@Ali04web
Copy link
Copy Markdown

Summary:

  • Applied design system components across admin pages
  • Standardized UI structure & layout consistency
  • Fixed JSX syntax issues
  • Improved component organization

Purpose:
Enhance UI consistency and maintainability without altering core functionality.

ebongard and others added 30 commits February 6, 2026 19:38
fix(security,perf): Critical security hardening and performance hotfixes
fix(security,perf,tests): Auth enforcement, query optimization, and critical test coverage (ebongard#73)
fix(security,perf): Medium-priority hardening, async safety, and test expansion (ebongard#75)
chore(quality): Low-priority cleanup, deprecation fixes, and edge-case tests (ebongard#77)
Implement LLM-based contradiction resolution (opt-in) that detects when
new facts update or invalidate existing memories, plus unconditional
history tracking for all memory modifications.

- Add MemoryHistory model with audit trail for create/update/delete
- Add _find_similar_memories, _resolve_contradiction, _apply_contradiction_resolution
- Add GET /{memory_id}/history API endpoint
- Add DE/EN contradiction resolution prompts (ADD/UPDATE/DELETE/NOOP)
- Add 3 config settings (memory_contradiction_resolution/threshold/top_k)
- Add alembic migration for memory_history table
- Add 27 new tests covering model, history, parsing, resolution, config, prompts

Co-Authored-By: Claude Opus 4.6 <[email protected]>
ebongard#69)

- Add 3 new env vars to ENVIRONMENT_VARIABLES.md with explanation
- Add MEMORY_CONTRADICTION_RESOLUTION to CLAUDE.md key config

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Both files were significantly outdated. README trimmed from landing page
with exhaustive API list to concise overview with table-based API summary.
FEATURES.md rewritten with 5 new sections (Conversation Memory, Agent
Router, Intent Feedback Learning, Proactive Notifications, LLM Config)
and removal of aspirational/non-existent features (Spotify, Grafana,
horizontal scaling, push notifications, face recognition).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Audit all docs/*.md against codebase, fix outdated content:
- SECURITY.md: Fix CSP (single policy, no dev/prod split), add rate
  limiting, circuit breaker, trusted proxies sections
- ENVIRONMENT_VARIABLES.md: Add multi-model Ollama vars, fix
  AGENT_MAX_STEPS default, add Paperless/Email MCP, remove Spotify,
  fix SEARXNG_API_URL, replace N8N_WEBHOOK_URL with MCP config
- DEPLOYMENT.md: Add OLLAMA_INTENT_MODEL/NUM_CTX, prod-cpu.yml,
  MCP section, replace N8N_WEBHOOK_URL
- ACCESS_CONTROL.md: Add missing plugins/notifications permissions
- TECHNICAL_DEBT.md: Update test counts (558→1642), file sizes
- PROACTIVE_NOTIFICATIONS.md: Add missing enrich webhook field
- OUTPUT_ROUTING.md: Fix ChatPage path after refactoring

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…st coverage (ebongard#87-ebongard#96)

Security: OTA path traversal prevention, pip package whitelist, TLS cert
verification (default on), auth token moved to header, mDNS warning,
2MB payload limit. Performance: hot-path imports to module level, audio
buffer cap, beamformer reshape, VAD pre-alloc, async TTS playback, LED
SPI write caching, button Timer. Tests: 91 new tests (128 total passing).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ongard#89)

Satellite now sends auth token as Authorization header instead of URL
query parameter. Added header fallback in authenticate_websocket() so
all WS endpoints (satellite, device, chat) accept both methods.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ops (ebongard#89)

2MB was only ~6s of speech. Raised to 10MB (~40s). On oversized payloads,
the session callback is still invoked with empty audio so the state
machine resets instead of hanging silently.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…bongard#97) (ebongard#98)

Add full support for the ReSpeaker 4-Mic Array (AC108 codec) on Pi Zero 2 W:
- arecord subprocess backend isolates I2S driver from onnxruntime (prevents kernel crash)
- AC108 channel 0 is silent (reference) — extract channel 1 for mic audio
- S32_LE/4ch → mono S16_LE conversion in capture loop

VAD reliability fixes:
- Replace wall-clock silence timer with audio-chunk counting (immune to CPU lag)
- Run VAD on raw audio instead of normalized (normalizer equalizes levels)
- Skip stop-word inference when no stop words configured (halves CPU load)
- RMS VAD recommended for 4-mic HAT (Silero unreliable under CPU contention)

Also includes: Ansible provisioning playbook, LED controller for 12-LED 4-mic HAT,
updated docs and tests.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
pip 25.3+ removed setuptools from vendored packages, causing
openai-whisper to fail during build isolation (missing pkg_resources).
Install whisper with --no-deps to bypass build isolation, matching
the approach already used in Dockerfile.gpu.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…uild

fix(backend): Fix openai-whisper build failure with pip>=25.3
…me WASM

Browser wake word detection failed because nginx served .mjs files as
application/octet-stream. With X-Content-Type-Options: nosniff, browsers
blocked the ES module import, preventing ONNX Runtime WASM from loading.

- Add location block for .mjs with default_type application/javascript
- Add .wasm, .onnx, .mjs to static asset caching regex
- Add E2E browser test for wake word functionality

Co-Authored-By: Claude Opus 4.6 <[email protected]>
fix(frontend): Serve .mjs files with correct MIME type for wake word
…d#101)

Phase 1 of chat document upload: upload button in chat input,
backend endpoint with quick text extraction via Docling, DB model
for tracking uploads, and attachment rendering in chat bubbles.

- ChatUpload model + Alembic migration (chat_uploads table)
- POST /api/chat/upload endpoint with format/size validation
- DocumentProcessor.extract_text_only() for quick extraction
- Paperclip upload button in ChatInput with pending attachments bar
- Attachment chips in ChatMessages (green=completed, red=failed)
- useDocumentUpload hook + ChatContext integration
- i18n translations (DE/EN) for all upload-related strings
- Backend tests (model + API) and frontend tests (4/4 passing)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(chat): Document upload in chat — Phase 1 (ebongard#101)
setuptools 76+ removed pkg_resources, breaking openai-whisper's
setup.py. Pin setuptools<76 and use --no-build-isolation to bypass
the isolated build environment.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…per-build

fix(backend): Fix openai-whisper build in Dockerfile.gpu
Phase 2 of chat document upload: extracted text from uploaded documents
is now injected into the LLM system prompt so the assistant can answer
questions about the document content.

- Add attachment_ids field to WSChatMessage
- Add document context prompt templates (DE/EN) in chat.yaml + agent.yaml
- Thread document_context parameter through OllamaService, AgentService,
  and all chat handler LLM call sites
- Frontend sends attachment_ids with message and clears chips after send
- Add chat_upload_max_context_chars config (default 50k chars)
- Add tests for context injection, truncation, and message parsing

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(chat): Inject uploaded document text as LLM context (ebongard#104)
…oads (ebongard#101) (ebongard#105)

* feat(chat): Add KB indexing, Paperless forwarding & quick actions for uploads (ebongard#101)

Phase 3 of chat document upload: adds file_path persistence, manual KB
indexing endpoint, Paperless-NGX forwarding via MCP, auto-index background
task, and a frontend quick actions menu (Add to KB, Send to Paperless,
Summarize) on attachment chips.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(chat): Persist and load attachment metadata in chat history (ebongard#101)

- Bulk-fetch ChatUpload records when loading history (chat.py)
- Save attachment_ids in user message metadata (chat_handler.py)
- Add .mcp.json to .gitignore (contains API keys)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat(chat): Add drag-and-drop file upload to chat input (ebongard#101)

Drop zone with visual indicator on the chat input area.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* test(e2e): Add post-deploy UI smoke tests with Playwright

Covers homepage, chat, navigation, dark mode, mobile viewport,
health endpoint, and console error checks against renfield.local.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…nup TTL (ebongard#101)

Phase 4 polish for chat document uploads:
- Multi-file upload via picker + drag-drop (sequential to existing endpoint)
- Per-file upload progress bars using axios onUploadProgress
- Email forwarding quick action via Email MCP (send_email with base64 attachment)
- Cleanup TTL: background task + endpoint to delete old non-indexed uploads
- EmailForwardDialog modal with recipient, subject, body fields
- 9 backend tests (email forward + cleanup) and 4 frontend tests

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(chat): Multi-file upload, progress bars, email forwarding & cleanup TTL (ebongard#101)
…ad support (ebongard#101)

- Add WebSocket connection registry (register/unregister/notify_session)
  for sending real-time notifications to chat sessions
- Background RAG indexing now sends document_processing, document_ready,
  and document_error messages to the client via WebSocket
- Frontend shows spinning loader during indexing, green "KB" badge when done
- Add png/jpg/jpeg to allowed upload extensions (OCR via DocumentProcessor)
- Add image MIME types to email forwarding mime_map
- 7 new backend tests (5 registry unit + 2 OCR upload) + 1 frontend test

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(chat): WS notifications & OCR image upload (ebongard#101)
…count param (ebongard#101) (ebongard#108)

- Enable chat_upload_auto_index by default (was False, blocking KB indexing)
- Quick actions dropdown opens downward (top-full) to avoid viewport clipping
- Add required 'account' parameter to email forward MCP call
- Add chat_upload_email_account config setting

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…bongard#101) (ebongard#109)

kb.documents fallback triggered a synchronous lazy-load inside async
context, causing MissingGreenlet crash. The _document_count transient
attribute from rag_service is always set, so the fallback to 0 is safe.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…gard#110)

Production server has no GPU. Default backend now uses Dockerfile (CPU).
GPU backend available as backend-gpu under --profile gpu.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Eduard van den Bongard and others added 26 commits February 21, 2026 23:07
- Chat/RAG: qwen3:14b with think=False for fast responses
- Intent: qwen3:8b with think=False for reliable JSON
- Agent: qwen3:14b on separate GPU with think=False
- Embeddings: qwen3-embedding:4b (2560 dim, HNSW indexes)
- Fix chat()/chat_stream() using self.model → self.chat_model
- Add get_classification_chat_kwargs() + extract_response_content()
  to ollama_service (chat, chat_stream, chat_with_rag,
  chat_stream_with_rag) and agent_service (agent loop, retry,
  _build_summary_answer)
- Update LLM_MODEL_GUIDE.md with production Qwen3 config

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(llm): Migrate all LLM roles to Qwen3 family (ebongard#225)
) (ebongard#228)

Align the frontend visual layer with the Renfield brand identity
(crimson bat with cyan neural-network eyes). Introduces custom fonts,
branded color palette, animations, sidebar rail, and consistent
page headers across all 30+ components.

- Fonts: Cormorant Variable (display) + DM Sans Variable (body)
- Colors: Crimson primary, cyan accent, cream, warm backgrounds
- Animations: Page transitions, typing dots, gentle pulse
- Login/Register: Dark gradient with cyan glow + bat logo
- Sidebar: Collapsible rail on desktop (hover to expand)
- Chat: Branded empty state, bouncing typing indicator
- Admin pages: Card headers with icon badges + display font
- Knowledge Graph: Promoted from admin to main navigation
- SVG logos: Updated font-family to Cormorant Variable

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Agent no longer loops 5x on search_media when Jellyfin returns 0 results.
Adds empty-result detection heuristic, per-tool counter in AgentContext,
and Jellyfin-specific search tip (album name only, verify artist after).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…loop

fix(agent): Break loop on repeated empty search results (ebongard#229)
…d#230)

Simple media transport commands (stop, pause, resume, next, previous)
now execute via a regex-based shortcut in chat_handler, avoiding 3 LLM
calls through the full agent loop. Reduces latency from ~5s to <1s.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ortcut

feat(media): Bypass agent loop for simple transport commands
…ol flow (ebongard#230)

Three bugs fixed from initial ebongard#230 implementation:

1. Shortcut ran AFTER memory retrieval (15s embedding + vector search),
   now runs BEFORE — transport commands execute in <100ms
2. last_media_room was never set because agent used renderer_name (not
   room_name) in tool call params — now captures both
3. Legacy intent path ran after shortcut due to if/else control flow
   bug — fixed with elif guard

Adds last_media_room to ConversationSessionState so follow-up commands
("Stop" after "Spiele X im Arbeitszimmer") resolve the room from
session memory instead of requiring explicit room context.

E2E verified on production: all transport commands <100ms.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…rtcut-v2

fix(media): Fix transport shortcut — pre-memory, room tracking, control flow
…#232) (ebongard#232)

Detect Jellyfin image URLs and common image extensions in assistant
messages and render them as <img> tags instead of plain text. Also
persist tool result data field in agent steps state.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Add documentation for all features since v1.1.0: album art in chat,
collapsible agent steps, media transport shortcuts, DLNA gapless album
playback, Paperless audit system, KG quality improvements (validation,
dedup, cleanup API), RAG improvements (knowledge_search tool, EasyOCR,
German FTS), Ollama fallback, satellite provisioning, and admin
maintenance page.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…ngard#234)

Render markdown links [text](url) and plain URLs as clickable <a> tags
that open in a new window. Extends the existing renderMessageContent()
to handle three content types: images, links, and text.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…bongard#236)

Add GENRE-SUCHE/GENRE SEARCH rules to DE+EN media agent prompts so the
LLM uses search_media(genre=...) instead of searching genre names as
title text.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
* feat(media): Add TuneIn radio search, playback, and favorites (ebongard#237)

Integrate TuneIn radio via new renfield-mcp-tunein MCP server (stdio).
Add internal.play_radio orchestration tool (search+resolve+play),
plus favorites CRUD (save/list/remove) with RadioFavorite DB model.
Update media agent role with radio MCP server and prompt rules (DE+EN).

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(media): Fix radio playback — prompt tuning, MCP tool lookup, DLNA routing (ebongard#237)

- Agent prompt: emphatic "Nur 2 Schritte!" directive so LLM auto-plays best
  match instead of listing search results
- mcp_client: execute_tool() now checks all_discovered_tools before fuzzy
  fallback, so internal tools can call prompt-filtered MCP tools
- internal_tools: play_radio resolves room target_type and routes DLNA rooms
  via mcp.dlna.play_tracks instead of HA-only _play_in_room

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…evaluation (ebongard#239)

Comprehensive analysis comparing Ollama with vLLM, SGLang, llama.cpp,
LocalAI, TensorRT-LLM, ExLlamaV2, Aphrodite, TabbyAPI, and KTransformers
on the current dual-GPU setup (RTX 5070 Ti + RTX 5060 Ti). Also evaluates
Mac Mini M4 Pro 64GB as potential replacement.

Key findings:
- M4 Pro cannot replace dual-GPU (5x less bandwidth)
- vLLM offers 5-90x improvement under concurrent load
- Prefix caching alone would cut intent TTFT from 4s to 0.6s
- Migration effort: 3-5 days thanks to LLMClient Protocol abstraction
- Recommended path: llama.cpp+llama-swap now, hybrid vLLM later

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
ebongard#240)

In-memory MediaFollowService tracks active media sessions per user and
hooks into presence detection to suspend/resume playback as users move.
Supports radio, single URL, and DLNA album sessions with conflict
resolution (room owner > role priority > first-come).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(media): Add Media Follow Me — playback follows user between rooms (ebongard#240)
Expose owner_id/owner_name in room API responses and add owner
selection dropdown to the room edit modal. Shows owner badge on
room cards when set. Required for Media Follow Me conflict resolution.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(rooms): Add room owner dropdown to admin UI
…ebongard#243)

Transform renfield.de landing page from generic OSS template to distinctive
showcase matching the app's identity. Cormorant serif + DM Sans body fonts,
crimson (#C41E3A) + cyan (#00FFD0) palette replacing off-brand sky-blue,
scroll-triggered reveal animations, grain texture overlay, radial gradient
backgrounds, browser chrome frame on screenshots, copy-to-clipboard on code
blocks, floating bat logo with glow, section dividers, GitHub stars badge.

Architecture SVGs updated: 11 MCP servers (added DLNA + Radio), Media Follow
service added. Light-mode architecture SVG created. Rooms dark-mode screenshot
replaced. Feature card "Smart Home" replaced with "Media Follow Me".

Co-Authored-By: Claude Opus 4.6 <[email protected]>
feat(site): Landing page design overhaul — dark atmospheric theme
…sistency (ebongard#245) (ebongard#246)

Add semantic button variants (btn-danger/success/ghost/icon-*), soften card
shadows, create reusable PageHeader/Alert/Badge components. Polish chat with
larger agent steps, suggestion chips, accent-cyan branding. Refactor RoomsPage
and SpeakersPage to use new design system and Modal component.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…ebongard#248)

Replace inline styles with PageHeader, Alert, Badge components and
semantic button utilities across 15 admin pages. Net reduction of
344 lines through consistent design system adoption.

Co-authored-by: Eduard van den Bongard <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
@Ali04web Ali04web force-pushed the feat/design-system-admin-pages branch from a9e4b5c to 98cd9a6 Compare February 23, 2026 22:06
@ebongard
Copy link
Copy Markdown
Owner

Hi @AH04dev, thanks for taking the time to contribute to Renfield! I appreciate the effort you put into standardizing the admin page UI components.

After reviewing the PR, I found several issues that would need to be addressed before this can be merged. I wanted to walk through them so you have a clear picture:

1. Unresolved Merge Conflicts

src/backend/services/internal_tools.py and src/backend/services/media_follow_service.py contain literal merge conflict markers (<<<<<<< HEAD / ======= / >>>>>>>). The backend would fail to start with these in place.

2. Backend Configuration Changes

src/backend/utils/config.py has all Docker service hostnames changed from their Docker Compose DNS names (postgres, redis, ollama) to localhost. This breaks the Docker-based deployment that all users rely on. It also removes several feature configurations (Knowledge Graph, Memory Contradiction Resolution, Essential Memories) that are actively used in production.

3. Feature Removals

Several working features were removed from configs and prompts:

  • config/agent_roles.yaml: DLNA and Radio removed from the media role, along with most internal tools (album playback, video playback, media control, radio favorites)
  • src/backend/prompts/agent.yaml: All DLNA, radio, and media control instructions stripped from agent prompts
  • src/backend/api/websocket/chat_handler.py: The essential memories retrieval (recently added feature) was removed

These are core features that users depend on daily.

4. Test Deletions

Around 2,500 lines of working tests were removed from test_conversation_memory.py and test_internal_tools.py, covering memory contradiction resolution, essential memories, media control, DLNA, radio, and knowledge search. We need these to stay.

5. JSX Syntax Issues from Automated Fixers

It looks like fix_jsx.py / fix_jsx.js scripts were run across the codebase, but they introduced some bugs:

  • React props moved inside className strings (e.g. ref={menuRef} and open={...} became part of the CSS class string)
  • Tailwind classes broken with spaces (w - 2.5 h - 2.5 instead of w-2.5 h-2.5)
  • Invalid JSX syntax like < div ...> and </div >

6. Duplicate MCP Server Entries

config/mcp_servers.yaml has the radio and dlna server configs added a second time — they already exist in the file.

7. Files That Shouldn't Be Committed

The PR includes several local development artifacts:

  • fix_jsx.py, src/frontend/fix_jsx.js, src/frontend/fix_jsx.py (temporary scripts)
  • src/backend/create_db.py (contains a hardcoded database password)
  • Various output/error files (*_output.txt, alembic_error.txt, eslint_report.json, etc.)
  • An empty root-level package-lock.json

Suggestion

The actual UI improvements (introducing Badge and Alert components, standardizing button classes) are a good direction! To move forward, I'd suggest:

  1. Start fresh from current main to avoid the merge conflicts and config drift
  2. Scope the PR to frontend-only changes — only touch files in src/frontend/src/pages/ and src/frontend/src/components/
  3. Don't use automated fixers on JSX — the manual approach is safer here
  4. Keep backend, config, and test files untouched unless there's a specific reason to change them
  5. Add changed files explicitly (git add <file>) rather than git add . to avoid committing temporary files

Happy to help if you have questions about the project setup or design system conventions. Thanks again for your interest in the project!

@Ali04web
Copy link
Copy Markdown
Author

Hi @ebongard ,

Thank you for the detailed review and for taking the time to outline the issues so clearly. I genuinely appreciate the thorough feedback.

I apologize for the problems in the PR — especially the unresolved merge conflicts, unintended backend/configuration changes, and the inclusion of local development artifacts. That’s on me

Based on your guidance, I’ll work on it

Thank you as well for the encouraging note about the Badge and Alert components — I’m glad the direction aligns with the project’s design goals.

If there are any specific frontend conventions or component patterns you’d like me to follow, I’d be happy to align before resubmitting.

Appreciate your patience and constructive feedback.

@ebongard
Copy link
Copy Markdown
Owner

Hi @AH04dev,

Thanks for the quick and thoughtful response! No worries at all — these things happen, especially when working across multiple branches.

Regarding frontend conventions — here are the key ones to keep in mind:

  • Dark mode: All components must use Tailwind dark: variants. Never hardcode colors.
  • i18n: All user-facing strings must use useTranslation() — add translations to both de.json and en.json.
  • Component classes: We have shared classes in index.css (.card, .input, .btn-primary, .btn-secondary) — prefer those over inline Tailwind for common patterns.
  • Scope: Keep the PR focused on frontend changes only — no backend or config file modifications.

I've also recently reorganized the project conventions into dedicated skill files and a slimmer CLAUDE.md on main, which should make it easier to reference.

Looking forward to your updated PR — the Badge and Alert work was a great start!

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