feature/improve-tag-organization-ux #8
@@ -252,19 +252,23 @@ function RecipeDetail() {
|
|||||||
<div className="tags-display-inline">
|
<div className="tags-display-inline">
|
||||||
<strong>Tags:</strong>
|
<strong>Tags:</strong>
|
||||||
{recipe.tags && recipe.tags.length > 0 ? (
|
{recipe.tags && recipe.tags.length > 0 ? (
|
||||||
recipe.tags.map(tag => (
|
recipe.tags.map(tagItem => {
|
||||||
<span key={tag} className="tag-chip-inline">
|
// Handle both string tags and object tags from API
|
||||||
{tag}
|
const tagName = typeof tagItem === 'string' ? tagItem : tagItem.tag?.name || tagItem.name;
|
||||||
<button
|
return (
|
||||||
onClick={() => handleRemoveTag(tag)}
|
<span key={tagName} className="tag-chip-inline">
|
||||||
disabled={savingTags}
|
{tagName}
|
||||||
className="tag-remove-btn-inline"
|
<button
|
||||||
title="Remove tag"
|
onClick={() => handleRemoveTag(tagName)}
|
||||||
>
|
disabled={savingTags}
|
||||||
×
|
className="tag-remove-btn-inline"
|
||||||
</button>
|
title="Remove tag"
|
||||||
</span>
|
>
|
||||||
))
|
×
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})
|
||||||
) : (
|
) : (
|
||||||
<span className="no-tags-inline">—</span>
|
<span className="no-tags-inline">—</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -107,65 +107,9 @@ function RecipeImport() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="import-actions">
|
<button type="submit" disabled={loading}>
|
||||||
<button type="submit" disabled={loading}>
|
{loading ? 'Importing...' : 'Import Recipe'}
|
||||||
{loading ? 'Importing...' : 'Import Recipe'}
|
</button>
|
||||||
</button>
|
|
||||||
|
|
||||||
<div className="import-tags-inline">
|
|
||||||
<label>Tags:</label>
|
|
||||||
<div className="import-tags-display">
|
|
||||||
{selectedTags.length > 0 ? (
|
|
||||||
selectedTags.map(tag => (
|
|
||||||
<span key={tag} className="tag-chip-inline">
|
|
||||||
{tag}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleRemoveTag(tag)}
|
|
||||||
className="tag-remove-btn-inline"
|
|
||||||
title="Remove tag"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<span className="no-tags-inline">None</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="import-tag-input">
|
|
||||||
<input
|
|
||||||
ref={tagInputRef}
|
|
||||||
type="text"
|
|
||||||
value={tagInput}
|
|
||||||
onChange={(e) => setTagInput(e.target.value)}
|
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
handleAddTag();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
placeholder="Add tag..."
|
|
||||||
list="import-available-tags"
|
|
||||||
className="tag-input-small"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleAddTag}
|
|
||||||
disabled={!tagInput.trim()}
|
|
||||||
className="tag-add-btn-small"
|
|
||||||
title="Add tag"
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
<datalist id="import-available-tags">
|
|
||||||
{availableTags.map(tag => (
|
|
||||||
<option key={tag.id} value={tag.name} />
|
|
||||||
))}
|
|
||||||
</datalist>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{error && <div className="error">{error}</div>}
|
{error && <div className="error">{error}</div>}
|
||||||
@@ -211,6 +155,63 @@ function RecipeImport() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Tag Management Section */}
|
||||||
|
<div className="import-tags-section" style={{ marginTop: '2rem', marginBottom: '2rem' }}>
|
||||||
|
<h3>Add Tags</h3>
|
||||||
|
<div className="import-tags-inline">
|
||||||
|
<div className="import-tags-display">
|
||||||
|
{selectedTags.length > 0 ? (
|
||||||
|
selectedTags.map(tag => (
|
||||||
|
<span key={tag} className="tag-chip-inline">
|
||||||
|
{tag}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleRemoveTag(tag)}
|
||||||
|
className="tag-remove-btn-inline"
|
||||||
|
title="Remove tag"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<span className="no-tags-inline">No tags yet</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="import-tag-input">
|
||||||
|
<input
|
||||||
|
ref={tagInputRef}
|
||||||
|
type="text"
|
||||||
|
value={tagInput}
|
||||||
|
onChange={(e) => setTagInput(e.target.value)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleAddTag();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
placeholder="Add tag..."
|
||||||
|
list="import-available-tags"
|
||||||
|
className="tag-input-small"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleAddTag}
|
||||||
|
disabled={!tagInput.trim()}
|
||||||
|
className="tag-add-btn-small"
|
||||||
|
title="Add tag"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
<datalist id="import-available-tags">
|
||||||
|
{availableTags.map(tag => (
|
||||||
|
<option key={tag.id} value={tag.name} />
|
||||||
|
))}
|
||||||
|
</datalist>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button onClick={handleSave} disabled={loading}>
|
<button onClick={handleSave} disabled={loading}>
|
||||||
Save Recipe
|
Save Recipe
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user