Files
basil/packages/web/src/styles/ManageIngredientMappings.css
Paul R Kartchner 3d1e5f0e14
Some checks failed
Security Scanning / Dependency License Check (pull_request) Has been cancelled
CI Pipeline / Lint Code (pull_request) Has been cancelled
CI Pipeline / Test API Package (pull_request) Has been cancelled
CI Pipeline / Test Web Package (pull_request) Has been cancelled
CI Pipeline / Test Shared Package (pull_request) Has been cancelled
Docker Build & Deploy / Build Docker Images (pull_request) Has been cancelled
E2E Tests / End-to-End Tests (pull_request) Has been cancelled
E2E Tests / E2E Tests (Mobile) (pull_request) Has been cancelled
Security Scanning / NPM Audit (pull_request) Has been cancelled
Security Scanning / Code Quality Scan (pull_request) Has been cancelled
Security Scanning / Docker Image Security (pull_request) Has been cancelled
CI Pipeline / Build All Packages (pull_request) Has been cancelled
CI Pipeline / Generate Coverage Report (pull_request) Has been cancelled
Docker Build & Deploy / Push Docker Images (pull_request) Has been cancelled
Docker Build & Deploy / Deploy to Staging (pull_request) Has been cancelled
Docker Build & Deploy / Deploy to Production (pull_request) Has been cancelled
Security Scanning / Security Summary (pull_request) Has been cancelled
feat: add database-backed ingredient-instruction mapping system
Implement comprehensive solution for managing ingredient-to-instruction
mappings in cooking mode. This moves from client-side state management
to persistent database storage, significantly improving reliability and
user experience.

## Key Changes

### Database & Backend
- Add IngredientInstructionMapping table with many-to-many relationship
- Implement automatic ingredient matching algorithm with smart name extraction
- Add API endpoints for mapping management (update, regenerate)
- Create migration script for existing recipes

### Frontend
- Simplify CookingMode to read-only display of stored mappings
- Add ManageIngredientMappings page with drag-and-drop editing
- Remove complex client-side state management (~200 lines)
- Add navigation between cooking mode and management interface

### Testing
- Add 11 comprehensive unit tests for ingredient matcher service
- Update integration tests with proper mocking
- All new features fully tested (24/25 API tests passing)

## Benefits
- Persistent mappings across all clients/devices
- Automatic generation on recipe import/creation
- User control via dedicated management interface
- Cleaner, more maintainable codebase

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-31 22:19:02 +00:00

403 lines
7.0 KiB
CSS

/* Manage Ingredient Mappings Styles */
.manage-mappings {
background-color: #fafafa;
min-height: 100vh;
padding: 1.5rem;
font-size: 1.05rem;
}
/* Header */
.manage-mappings-header {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
padding-bottom: 1.5rem;
border-bottom: 3px solid #1976d2;
}
.manage-mappings-title h1 {
font-size: 2rem;
margin: 0;
color: #1976d2;
line-height: 1.2;
}
.manage-mappings-title h2 {
font-size: 1.5rem;
margin: 0.5rem 0 0 0;
color: #555;
font-weight: normal;
}
.manage-mappings-controls {
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: center;
}
.manage-mappings-controls button {
padding: 0.75rem 1.5rem;
font-size: 1rem;
border: none;
border-radius: 8px;
cursor: pointer;
background-color: #1976d2;
color: white;
font-weight: 500;
transition: background-color 0.2s;
}
.manage-mappings-controls button:hover:not(:disabled) {
background-color: #0d47a1;
}
.manage-mappings-controls button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.manage-mappings-controls .exit-btn {
background-color: #757575;
}
.manage-mappings-controls .exit-btn:hover {
background-color: #424242;
}
.manage-mappings-controls .save-btn {
background-color: #2e7d32;
}
.manage-mappings-controls .save-btn:hover:not(:disabled) {
background-color: #1b5e20;
}
.manage-mappings-controls .regenerate-btn {
background-color: #ff9800;
}
.manage-mappings-controls .regenerate-btn:hover:not(:disabled) {
background-color: #f57c00;
}
.manage-mappings-controls .cooking-mode-btn {
background-color: #2e7d32;
}
.manage-mappings-controls .cooking-mode-btn:hover {
background-color: #1b5e20;
}
/* Unsaved changes banner */
.unsaved-changes-banner {
background-color: #fff3e0;
border: 2px solid #ff9800;
border-radius: 8px;
padding: 1rem 1.5rem;
margin-bottom: 1.5rem;
font-weight: 500;
color: #e65100;
}
/* Instructions help */
.instructions-help {
background-color: #e3f2fd;
border: 2px solid #1976d2;
border-radius: 8px;
padding: 1rem 1.5rem;
margin-bottom: 1.5rem;
}
.instructions-help p {
margin: 0 0 0.5rem 0;
color: #0d47a1;
}
.instructions-help ul {
margin: 0;
padding-left: 1.5rem;
color: #1565c0;
}
.instructions-help li {
margin: 0.25rem 0;
}
/* Ingredients section */
.manage-mappings-ingredients-section {
background-color: white;
padding: 2rem;
border-radius: 12px;
margin-bottom: 2rem;
border: 2px solid #2e7d32;
}
.manage-mappings-ingredients-section .hint-text {
font-size: 0.9rem;
color: #666;
font-weight: normal;
font-style: italic;
}
.manage-mappings-ingredients-section h2 {
margin-top: 0;
font-size: 1.75rem;
color: #2e7d32;
margin-bottom: 1.5rem;
}
.manage-mappings-ingredients-section h3 {
font-size: 1.3rem;
color: #1b5e20;
margin-top: 1.5rem;
margin-bottom: 1rem;
}
.manage-mappings-ingredients-section ul {
list-style: none;
padding: 0;
margin: 0;
}
.manage-mappings-ingredients-section li.ingredient-item.draggable-source {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
border-radius: 4px;
cursor: grab;
transition: background-color 0.2s;
border-bottom: 1px solid #e0e0e0;
margin-bottom: 0.5rem;
}
.manage-mappings-ingredients-section li.ingredient-item.draggable-source:hover {
background-color: #e8f5e9;
}
.manage-mappings-ingredients-section li.ingredient-item.draggable-source:active {
cursor: grabbing;
}
.ingredient-section {
margin-bottom: 2rem;
}
/* Instructions section */
.manage-mappings-instructions {
margin-bottom: 3rem;
}
.manage-mappings-instructions h2 {
font-size: 1.75rem;
color: #1976d2;
margin-bottom: 1.5rem;
}
/* Section headers (for multi-section recipes) */
.instruction-section {
margin-bottom: 3rem;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding-bottom: 0.75rem;
border-bottom: 2px solid #1976d2;
}
.section-header h3 {
font-size: 1.5rem;
margin: 0;
color: #0d47a1;
}
.section-timing {
font-size: 1rem;
color: #666;
background-color: #fff3e0;
padding: 0.5rem 1rem;
border-radius: 6px;
font-weight: 500;
}
/* Individual instruction steps */
.instruction-step {
background-color: white;
padding: 1.5rem;
border-radius: 12px;
margin-bottom: 1.5rem;
border: 2px solid #e0e0e0;
transition: all 0.3s ease;
}
.instruction-step:hover {
border-color: #1976d2;
}
.step-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.step-number {
font-size: 1.3rem;
font-weight: 700;
color: #1976d2;
}
.instruction-timing {
font-size: 1rem;
color: #d84315;
background-color: #fff3e0;
padding: 0.5rem 1rem;
border-radius: 6px;
font-weight: 500;
}
.step-text {
font-size: 1.2rem;
line-height: 1.8;
color: #212121;
margin-bottom: 1rem;
}
/* Inline ingredients */
.inline-ingredients {
background-color: #f1f8e9;
padding: 1rem 1.25rem;
border-radius: 8px;
margin-top: 1rem;
border-left: 4px solid #2e7d32;
}
.inline-ingredients strong {
color: #1b5e20;
font-size: 1.05rem;
display: block;
margin-bottom: 0.5rem;
}
.inline-ingredients ul {
list-style: none;
padding: 0;
margin: 0;
}
.inline-ingredients li.ingredient-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
padding: 0.5rem;
border-radius: 4px;
transition: background-color 0.2s;
margin-bottom: 0.25rem;
}
.inline-ingredients li.ingredient-item:hover {
background-color: #dcedc8;
}
.inline-ingredients .no-ingredients {
color: #757575;
font-style: italic;
margin: 0.5rem 0;
}
.drag-handle {
color: #9e9e9e;
font-size: 1rem;
cursor: grab;
user-select: none;
}
.ingredient-text {
flex: 1;
font-size: 1.05rem;
}
.remove-ingredient-btn {
background: none;
border: none;
color: #d32f2f;
font-size: 1.25rem;
cursor: pointer;
padding: 0.25rem 0.5rem;
border-radius: 4px;
transition: background-color 0.2s;
line-height: 1;
}
.remove-ingredient-btn:hover {
background-color: #ffebee;
}
/* Step images */
.step-image {
width: 100%;
max-width: 600px;
border-radius: 8px;
margin-top: 1rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* Footer */
.manage-mappings-footer {
text-align: center;
padding: 2rem 0;
border-top: 2px solid #e0e0e0;
}
.save-btn-large {
padding: 1rem 3rem;
font-size: 1.25rem;
border: none;
border-radius: 8px;
cursor: pointer;
background-color: #2e7d32;
color: white;
font-weight: 600;
transition: background-color 0.2s;
}
.save-btn-large:hover:not(:disabled) {
background-color: #1b5e20;
}
.save-btn-large:disabled {
background-color: #ccc;
cursor: not-allowed;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.manage-mappings-title h1 {
font-size: 1.75rem;
}
.manage-mappings-controls {
flex-direction: column;
width: 100%;
}
.manage-mappings-controls button {
width: 100%;
}
.step-text {
font-size: 1.1rem;
}
.inline-ingredients li {
font-size: 1rem;
}
}