fix(frontend): let a tag be created/edited without a colour
A native <input type="color"> always holds a value, so the form always sent the input's default colour and a tag could never be colourless. Add a "Color" checkbox gating the swatch: off by default on the new-tag form (so tags are colourless unless opted in) and initialised from the tag on the edit form, which can now clear a colour. Sends color: null when off. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
let name = $state('');
|
let name = $state('');
|
||||||
let notes = $state('');
|
let notes = $state('');
|
||||||
|
// A native <input type="color"> always holds a value, so a separate flag tracks
|
||||||
|
// whether the tag has a colour at all — letting it be cleared back to none.
|
||||||
|
let hasColor = $state(false);
|
||||||
let color = $state('#444455');
|
let color = $state('#444455');
|
||||||
let categoryId = $state('');
|
let categoryId = $state('');
|
||||||
let isPublic = $state(false);
|
let isPublic = $state(false);
|
||||||
@@ -43,6 +46,7 @@
|
|||||||
|
|
||||||
name = t.name ?? '';
|
name = t.name ?? '';
|
||||||
notes = t.notes ?? '';
|
notes = t.notes ?? '';
|
||||||
|
hasColor = !!t.color;
|
||||||
color = t.color ? `#${t.color}` : '#444455';
|
color = t.color ? `#${t.color}` : '#444455';
|
||||||
categoryId = t.category_id ?? '';
|
categoryId = t.category_id ?? '';
|
||||||
isPublic = t.is_public ?? false;
|
isPublic = t.is_public ?? false;
|
||||||
@@ -61,7 +65,7 @@
|
|||||||
await api.patch(`/tags/${tagId}`, {
|
await api.patch(`/tags/${tagId}`, {
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
notes: notes.trim() || null,
|
notes: notes.trim() || null,
|
||||||
color: color.slice(1),
|
color: hasColor ? color.slice(1) : null,
|
||||||
category_id: categoryId || null,
|
category_id: categoryId || null,
|
||||||
is_public: isPublic
|
is_public: isPublic
|
||||||
});
|
});
|
||||||
@@ -139,8 +143,18 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="field color-field">
|
<div class="field color-field">
|
||||||
<label class="label" for="color">Color</label>
|
<label class="label color-label">
|
||||||
<input id="color" class="color-input" type="color" bind:value={color} />
|
<input type="checkbox" class="color-check" bind:checked={hasColor} />
|
||||||
|
Color
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="color"
|
||||||
|
class="color-input"
|
||||||
|
type="color"
|
||||||
|
bind:value={color}
|
||||||
|
disabled={!hasColor}
|
||||||
|
aria-label="Tag color"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -339,6 +353,18 @@
|
|||||||
border-color: var(--color-accent);
|
border-color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-check {
|
||||||
|
cursor: pointer;
|
||||||
|
accent-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
.color-input {
|
.color-input {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
@@ -349,6 +375,11 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-input:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.textarea {
|
.textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
let name = $state('');
|
let name = $state('');
|
||||||
let notes = $state('');
|
let notes = $state('');
|
||||||
|
// A native <input type="color"> always holds a value, so a separate flag tracks
|
||||||
|
// whether the tag should have a color at all. Off by default → no colour unless
|
||||||
|
// the user opts in (otherwise the tag falls back to its category / the default).
|
||||||
|
let hasColor = $state(false);
|
||||||
let color = $state('#444455');
|
let color = $state('#444455');
|
||||||
let categoryId = $state('');
|
let categoryId = $state('');
|
||||||
let isPublic = $state(false);
|
let isPublic = $state(false);
|
||||||
@@ -27,7 +31,7 @@
|
|||||||
await api.post('/tags', {
|
await api.post('/tags', {
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
notes: notes.trim() || null,
|
notes: notes.trim() || null,
|
||||||
color: color.slice(1), // strip #
|
color: hasColor ? color.slice(1) : null, // strip #; null = no colour
|
||||||
category_id: categoryId || null,
|
category_id: categoryId || null,
|
||||||
is_public: isPublic
|
is_public: isPublic
|
||||||
});
|
});
|
||||||
@@ -86,8 +90,18 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="field color-field">
|
<div class="field color-field">
|
||||||
<label class="label" for="color">Color</label>
|
<label class="label color-label">
|
||||||
<input id="color" class="color-input" type="color" bind:value={color} />
|
<input type="checkbox" class="color-check" bind:checked={hasColor} />
|
||||||
|
Color
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="color"
|
||||||
|
class="color-input"
|
||||||
|
type="color"
|
||||||
|
bind:value={color}
|
||||||
|
disabled={!hasColor}
|
||||||
|
aria-label="Tag color"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -235,6 +249,18 @@
|
|||||||
border-color: var(--color-accent);
|
border-color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-check {
|
||||||
|
cursor: pointer;
|
||||||
|
accent-color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
.color-input {
|
.color-input {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
@@ -245,6 +271,11 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-input:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.textarea {
|
.textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
Reference in New Issue
Block a user