feature/improve-tag-organization-ux #8
@@ -20,6 +20,7 @@ function Cookbooks() {
|
||||
const [cookbookTagInput, setCookbookTagInput] = useState('');
|
||||
const [cookbookTagFilterInput, setCookbookTagFilterInput] = useState('');
|
||||
const [availableTags, setAvailableTags] = useState<Tag[]>([]);
|
||||
const [autoAddCollapsed, setAutoAddCollapsed] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
@@ -244,113 +245,158 @@ function Cookbooks() {
|
||||
<div className="modal" onClick={(e) => e.stopPropagation()}>
|
||||
<h2>Create New Cookbook</h2>
|
||||
<form onSubmit={handleCreateCookbook}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-name">Name *</label>
|
||||
<input
|
||||
id="cookbook-name"
|
||||
type="text"
|
||||
value={newCookbookName}
|
||||
onChange={(e) => setNewCookbookName(e.target.value)}
|
||||
placeholder="e.g., Family Favorites, Holiday Recipes"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-description">Description</label>
|
||||
<textarea
|
||||
id="cookbook-description"
|
||||
value={newCookbookDescription}
|
||||
onChange={(e) => setNewCookbookDescription(e.target.value)}
|
||||
placeholder="Describe this cookbook..."
|
||||
rows={3}
|
||||
/>
|
||||
{/* SECTION 1: BASIC INFO */}
|
||||
<div className="form-section">
|
||||
<div className="form-section-header">
|
||||
<span className="form-section-icon">📝</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Basic Information</h2>
|
||||
<p>Give your cookbook a name and description</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-section-content">
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-name">Name *</label>
|
||||
<input
|
||||
id="cookbook-name"
|
||||
type="text"
|
||||
value={newCookbookName}
|
||||
onChange={(e) => setNewCookbookName(e.target.value)}
|
||||
placeholder="e.g., Family Favorites, Holiday Recipes"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-description">Description</label>
|
||||
<textarea
|
||||
id="cookbook-description"
|
||||
value={newCookbookDescription}
|
||||
onChange={(e) => setNewCookbookDescription(e.target.value)}
|
||||
placeholder="Describe this cookbook..."
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Auto-Add Tags (Optional)</label>
|
||||
<p className="help-text">Recipes with these tags will be automatically added to this cookbook</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
{/* SECTION 2: ORGANIZE THIS COOKBOOK */}
|
||||
<div className="form-section">
|
||||
<div className="form-section-header">
|
||||
<span className="form-section-icon">📋</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Organize This Cookbook</h2>
|
||||
<p>Tag this cookbook so you can find it later</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddTag())}
|
||||
placeholder="Add tag"
|
||||
list="available-tags-modal"
|
||||
/>
|
||||
<button type="button" onClick={handleAddTag} className="btn-add-filter">+</button>
|
||||
<div className="form-section-content">
|
||||
<div className="form-group">
|
||||
<label>Cookbook Tags</label>
|
||||
<p className="help-text">Examples: "holiday", "meal-prep", "family-favorites"</p>
|
||||
<div className="filter-chips">
|
||||
{cookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagInput}
|
||||
onChange={(e) => setCookbookTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTag())}
|
||||
placeholder="Add a tag"
|
||||
list="available-cookbook-tags"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTag} className="btn-add-filter">+</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-tags">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
<datalist id="available-tags-modal">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Cookbook Tags (Optional)</label>
|
||||
<p className="help-text">Tags to categorize this cookbook (e.g., "holiday", "quick-meals")</p>
|
||||
<div className="filter-chips">
|
||||
{cookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
{/* SECTION 3: AUTO-ADD CONTENT (COLLAPSIBLE) */}
|
||||
<div className={`form-section collapsible ${autoAddCollapsed ? 'collapsed' : ''}`}>
|
||||
<div className="form-section-header" onClick={() => setAutoAddCollapsed(!autoAddCollapsed)}>
|
||||
<span className="form-section-icon">⚡</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Auto-Add Content (Optional)</h2>
|
||||
<p>Automatically add recipes and cookbooks</p>
|
||||
</div>
|
||||
<span className="form-section-toggle">▼</span>
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagInput}
|
||||
onChange={(e) => setCookbookTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTag())}
|
||||
placeholder="Add tag"
|
||||
list="available-cookbook-tags"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTag} className="btn-add-filter">+</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-tags">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
<div className="form-section-content">
|
||||
{/* Subsection: By Recipe Tags */}
|
||||
<div className="form-subsection">
|
||||
<div className="form-subsection-header">
|
||||
<span className="form-subsection-icon">🍲</span>
|
||||
<h3>By Recipe Tags</h3>
|
||||
</div>
|
||||
<p className="help-text">Recipes tagged with these will be auto-added. Example: "vegetarian"</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddTag())}
|
||||
placeholder="Add a tag"
|
||||
list="available-tags-modal"
|
||||
/>
|
||||
<button type="button" onClick={handleAddTag} className="btn-add-filter">+</button>
|
||||
</div>
|
||||
<datalist id="available-tags-modal">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Auto-Include Cookbooks by Tags (Optional)</label>
|
||||
<p className="help-text">Other cookbooks with these tags will be automatically included</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterCookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTagFilter(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
{/* Subsection: By Cookbook Tags */}
|
||||
<div className="form-subsection">
|
||||
<div className="form-subsection-header">
|
||||
<span className="form-subsection-icon">📚</span>
|
||||
<h3>By Cookbook Tags</h3>
|
||||
</div>
|
||||
<p className="help-text">Include cookbooks tagged with these. Example: "italian"</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterCookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTagFilter(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagFilterInput}
|
||||
onChange={(e) => setCookbookTagFilterInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTagFilter())}
|
||||
placeholder="Add a tag"
|
||||
list="available-cookbook-filter-tags"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTagFilter} className="btn-add-filter">+</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-filter-tags">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagFilterInput}
|
||||
onChange={(e) => setCookbookTagFilterInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTagFilter())}
|
||||
placeholder="Add tag to filter by"
|
||||
list="available-cookbook-filter-tags"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTagFilter} className="btn-add-filter">+</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-filter-tags">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="modal-actions">
|
||||
|
||||
@@ -26,6 +26,7 @@ function EditCookbook() {
|
||||
const [cookbookTagInput, setCookbookTagInput] = useState('');
|
||||
const [cookbookTagFilterInput, setCookbookTagFilterInput] = useState('');
|
||||
const [availableTags, setAvailableTags] = useState<Tag[]>([]);
|
||||
const [autoAddCollapsed, setAutoAddCollapsed] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
@@ -198,30 +199,40 @@ function EditCookbook() {
|
||||
</header>
|
||||
|
||||
<form onSubmit={handleSubmit} className="edit-cookbook-form">
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-name">Name *</label>
|
||||
<input
|
||||
id="cookbook-name"
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="e.g., Family Favorites, Holiday Recipes"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{/* SECTION 1: BASIC INFO */}
|
||||
<div className="form-section">
|
||||
<div className="form-section-header">
|
||||
<span className="form-section-icon">📝</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Basic Information</h2>
|
||||
<p>Give your cookbook a name and description</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-section-content">
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-name">Name *</label>
|
||||
<input
|
||||
id="cookbook-name"
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="e.g., Family Favorites, Holiday Recipes"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-description">Description</label>
|
||||
<textarea
|
||||
id="cookbook-description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Describe this cookbook..."
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cookbook-description">Description</label>
|
||||
<textarea
|
||||
id="cookbook-description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Describe this cookbook..."
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<div className="form-group">
|
||||
<label>Cover Image</label>
|
||||
{coverImageUrl && (
|
||||
<div className="image-preview">
|
||||
@@ -309,104 +320,139 @@ function EditCookbook() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Auto-Add Tags</label>
|
||||
<p className="help-text">
|
||||
Recipes with these tags will be automatically added to this cookbook
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddTag())}
|
||||
placeholder="Add tag"
|
||||
list="available-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddTag} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
<datalist id="available-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Cookbook Tags</label>
|
||||
<p className="help-text">
|
||||
Tags to categorize this cookbook (e.g., "holiday", "quick-meals", "vegetarian")
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{cookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
{/* SECTION 2: ORGANIZE THIS COOKBOOK */}
|
||||
<div className="form-section">
|
||||
<div className="form-section-header">
|
||||
<span className="form-section-icon">📋</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Organize This Cookbook</h2>
|
||||
<p>Tag this cookbook so you can find it later and include it in other cookbooks</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagInput}
|
||||
onChange={(e) => setCookbookTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTag())}
|
||||
placeholder="Add tag"
|
||||
list="available-cookbook-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTag} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
<div className="form-section-content">
|
||||
<div className="form-group">
|
||||
<label>Cookbook Tags</label>
|
||||
<p className="help-text">
|
||||
Examples: "holiday", "meal-prep", "family-favorites", "quick-meals"
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{cookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagInput}
|
||||
onChange={(e) => setCookbookTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTag())}
|
||||
placeholder="Add a tag"
|
||||
list="available-cookbook-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTag} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
<datalist id="available-cookbook-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>Auto-Include Cookbooks by Tags</label>
|
||||
<p className="help-text">
|
||||
Other cookbooks with these tags will be automatically included in this cookbook
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterCookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTagFilter(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
{/* SECTION 3: AUTO-ADD CONTENT (COLLAPSIBLE) */}
|
||||
<div className={`form-section collapsible ${autoAddCollapsed ? 'collapsed' : ''}`}>
|
||||
<div className="form-section-header" onClick={() => setAutoAddCollapsed(!autoAddCollapsed)}>
|
||||
<span className="form-section-icon">⚡</span>
|
||||
<div className="form-section-title">
|
||||
<h2>Auto-Add Content (Optional)</h2>
|
||||
<p>Automatically add recipes and cookbooks matching these criteria</p>
|
||||
</div>
|
||||
<span className="form-section-toggle">▼</span>
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagFilterInput}
|
||||
onChange={(e) => setCookbookTagFilterInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTagFilter())}
|
||||
placeholder="Add tag to filter by"
|
||||
list="available-cookbook-filter-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTagFilter} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
<div className="form-section-content">
|
||||
{/* Subsection: By Recipe Tags */}
|
||||
<div className="form-subsection">
|
||||
<div className="form-subsection-header">
|
||||
<span className="form-subsection-icon">🍲</span>
|
||||
<h3>By Recipe Tags</h3>
|
||||
</div>
|
||||
<p className="help-text">
|
||||
Recipes tagged with any of these will be automatically added to this cookbook.
|
||||
Example: Add "vegetarian" to auto-include all vegetarian recipes.
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveTag(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddTag())}
|
||||
placeholder="Add a tag"
|
||||
list="available-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddTag} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
<datalist id="available-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
{/* Subsection: By Cookbook Tags */}
|
||||
<div className="form-subsection">
|
||||
<div className="form-subsection-header">
|
||||
<span className="form-subsection-icon">📚</span>
|
||||
<h3>By Cookbook Tags</h3>
|
||||
</div>
|
||||
<p className="help-text">
|
||||
Include other cookbooks tagged with these. Example: Add "italian" to include all Italian-themed cookbooks.
|
||||
</p>
|
||||
<div className="filter-chips">
|
||||
{autoFilterCookbookTags.map(tag => (
|
||||
<span key={tag} className="filter-chip">
|
||||
{tag}
|
||||
<button type="button" onClick={() => handleRemoveCookbookTagFilter(tag)}>×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="input-with-button">
|
||||
<input
|
||||
type="text"
|
||||
value={cookbookTagFilterInput}
|
||||
onChange={(e) => setCookbookTagFilterInput(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddCookbookTagFilter())}
|
||||
placeholder="Add a tag"
|
||||
list="available-cookbook-filter-tags-edit"
|
||||
/>
|
||||
<button type="button" onClick={handleAddCookbookTagFilter} className="btn-add-filter">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
<datalist id="available-cookbook-filter-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
<datalist id="available-cookbook-filter-tags-edit">
|
||||
{availableTags.map(tag => (
|
||||
<option key={tag.id} value={tag.name} />
|
||||
))}
|
||||
</datalist>
|
||||
</div>
|
||||
|
||||
<div className="form-actions">
|
||||
|
||||
@@ -324,6 +324,111 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Form Sections with Visual Hierarchy */
|
||||
.form-section {
|
||||
background: #fafafa;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.form-section-icon {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.form-section-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-section-title h2 {
|
||||
font-size: 1.3rem;
|
||||
color: #2e7d32;
|
||||
margin: 0 0 0.25rem 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-section-title p {
|
||||
font-size: 0.9rem;
|
||||
color: #757575;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.form-section-content {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Collapsible Sections */
|
||||
.form-section.collapsible .form-section-header {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background-color 0.2s;
|
||||
margin: -1.5rem -1.5rem 0 -1.5rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
.form-section.collapsible .form-section-header:hover {
|
||||
background-color: rgba(46, 125, 50, 0.05);
|
||||
}
|
||||
|
||||
.form-section-toggle {
|
||||
font-size: 1.2rem;
|
||||
color: #2e7d32;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.form-section.collapsed .form-section-toggle {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.form-section.collapsed .form-section-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Subsection Styling */
|
||||
.form-subsection {
|
||||
background: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-subsection:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-subsection-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-subsection-icon {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.form-subsection-header h3 {
|
||||
font-size: 1.1rem;
|
||||
color: #424242;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.filter-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -74,6 +74,111 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Form Sections with Visual Hierarchy */
|
||||
.form-section {
|
||||
background: #fafafa;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.form-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.form-section-icon {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.form-section-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-section-title h2 {
|
||||
font-size: 1.3rem;
|
||||
color: #2e7d32;
|
||||
margin: 0 0 0.25rem 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-section-title p {
|
||||
font-size: 0.9rem;
|
||||
color: #757575;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.form-section-content {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Collapsible Sections */
|
||||
.form-section.collapsible .form-section-header {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background-color 0.2s;
|
||||
margin: -1.5rem -1.5rem 0 -1.5rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
.form-section.collapsible .form-section-header:hover {
|
||||
background-color: rgba(46, 125, 50, 0.05);
|
||||
}
|
||||
|
||||
.form-section-toggle {
|
||||
font-size: 1.2rem;
|
||||
color: #2e7d32;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.form-section.collapsed .form-section-toggle {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.form-section.collapsed .form-section-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Subsection Styling */
|
||||
.form-subsection {
|
||||
background: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-subsection:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-subsection-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-subsection-icon {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.form-subsection-header h3 {
|
||||
font-size: 1.1rem;
|
||||
color: #424242;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.filter-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user